diff options
934 files changed, 21449 insertions, 14011 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 9e308435c9bc..ce311d01cd58 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -71,6 +71,9 @@ aconfig_srcjars = [ ":android.appwidget.flags-aconfig-java{.generated_srcjars}", ":android.webkit.flags-aconfig-java{.generated_srcjars}", ":android.provider.flags-aconfig-java{.generated_srcjars}", + ":android.chre.flags-aconfig-java{.generated_srcjars}", + ":android.speech.flags-aconfig-java{.generated_srcjars}", + ":power_flags_lib{.generated_srcjars}", ] filegroup { @@ -196,7 +199,7 @@ java_aconfig_library { aconfig_declarations { name: "android.nfc.flags-aconfig", package: "android.nfc", - srcs: ["core/java/android/nfc/*.aconfig"], + srcs: ["nfc/java/android/nfc/*.aconfig"], } cc_aconfig_library { @@ -214,7 +217,7 @@ cc_aconfig_library { java_aconfig_library { name: "android.nfc.flags-aconfig-java", aconfig_declarations: "android.nfc.flags-aconfig", - min_sdk_version: "VanillaIceCream", + min_sdk_version: "34", apex_available: [ "//apex_available:platform", "com.android.nfcservices", @@ -480,8 +483,8 @@ java_aconfig_library { apex_available: [ "//apex_available:platform", "com.android.permission", + "com.android.nfcservices", ], - } // SQLite @@ -743,6 +746,11 @@ aconfig_declarations { java_aconfig_library { name: "android.service.chooser.flags-aconfig-java", aconfig_declarations: "android.service.chooser.flags-aconfig", + min_sdk_version: "34", + apex_available: [ + "//apex_available:platform", + "com.android.nfcservices", + ], defaults: ["framework-minus-apex-aconfig-java-defaults"], } @@ -905,3 +913,30 @@ java_aconfig_library { aconfig_declarations: "android.provider.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// ContextHub +java_aconfig_library { + name: "android.chre.flags-aconfig-java", + aconfig_declarations: "chre_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +// Speech +aconfig_declarations { + name: "android.speech.flags-aconfig", + package: "android.speech.flags", + srcs: ["core/java/android/speech/flags/*.aconfig"], +} + +java_aconfig_library { + name: "android.speech.flags-aconfig-java", + aconfig_declarations: "android.speech.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +// Power +java_aconfig_library { + name: "power_flags_lib", + aconfig_declarations: "power_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} diff --git a/Android.bp b/Android.bp index f3b2ebb4fc17..a3e39018e147 100644 --- a/Android.bp +++ b/Android.bp @@ -175,9 +175,6 @@ java_library { // and remove this line. "//frameworks/base/tools/hoststubgen:__subpackages__", ], - lint: { - baseline_filename: "lint-baseline.xml", - }, } // AIDL files under these paths are mixture of public and private ones. @@ -270,9 +267,6 @@ java_library { ], sdk_version: "core_platform", installable: false, - lint: { - baseline_filename: "lint-baseline.xml", - }, } // NOTE: This filegroup is exposed for vendor libraries to depend on and is referenced in @@ -437,13 +431,9 @@ java_library { name: "framework-non-updatable-unbundled-impl-libs", static_libs: [ "framework-location.impl", - "framework-nfc.impl", ], sdk_version: "core_platform", installable: false, - lint: { - baseline_filename: "lint-baseline.xml", - }, } // Separated so framework-minus-apex-defaults can be used without the libs dependency @@ -487,9 +477,6 @@ java_library { ], compile_dex: false, headers_only: true, - lint: { - baseline_filename: "lint-baseline.xml", - }, } java_library { @@ -534,7 +521,7 @@ java_library { }, lint: { enabled: false, - baseline_filename: "lint-baseline.xml", + }, } @@ -559,9 +546,6 @@ java_library { ], sdk_version: "core_platform", apex_available: ["//apex_available:platform"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } java_library { @@ -577,9 +561,6 @@ java_library { "calendar-provider-compat-config", "contacts-provider-platform-compat-config", ], - lint: { - baseline_filename: "lint-baseline.xml", - }, } platform_compat_config { @@ -634,9 +615,6 @@ java_library { "rappor", ], dxflags: ["--core-library"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } // utility classes statically linked into framework-wifi and dynamically linked diff --git a/apct-tests/perftests/permission/Android.bp b/apct-tests/perftests/permission/Android.bp new file mode 100644 index 000000000000..b80a6af612ec --- /dev/null +++ b/apct-tests/perftests/permission/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "PermissionServicePerfTests", + + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], + + static_libs: [ + "platform-compat-test-rules", + "androidx.appcompat_appcompat", + "androidx.test.rules", + "androidx.test.ext.junit", + "androidx.annotation_annotation", + "apct-perftests-utils", + "androidx.benchmark_benchmark-common", + "androidx.benchmark_benchmark-junit4", + "collector-device-lib-platform", + "cts-install-lib-java", + ], + + libs: ["android.test.base"], + + platform_apis: true, + + test_suites: ["device-tests"], + + data: [ + ":UsePermissionApp0", + ":UsePermissionApp1", + ":UsePermissionApp2", + ":UsePermissionApp3", + ":UsePermissionApp4", + ":UsePermissionApp5", + ":UsePermissionApp6", + ":UsePermissionApp7", + ":UsePermissionApp8", + ":UsePermissionApp9", + ":UsePermissionApp10", + ":UsePermissionApp11", + ":UsePermissionApp12", + ":UsePermissionApp13", + ":UsePermissionApp14", + ":UsePermissionApp15", + ":UsePermissionApp16", + ":UsePermissionApp17", + ":UsePermissionApp18", + ":UsePermissionApp19", + ":UsePermissionApp20", + ":UsePermissionApp21", + ":UsePermissionApp22", + ":UsePermissionApp23", + ":UsePermissionApp24", + ":UsePermissionApp25", + ":UsePermissionApp26", + ":UsePermissionApp27", + ":UsePermissionApp28", + ":UsePermissionApp29", + ":perfetto_artifacts", + ], + + certificate: "platform", + +} diff --git a/apct-tests/perftests/permission/AndroidManifest.xml b/apct-tests/perftests/permission/AndroidManifest.xml new file mode 100644 index 000000000000..fa29ad0404da --- /dev/null +++ b/apct-tests/perftests/permission/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.perftests.permission"> + + <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> + + <application> + <uses-library android:name="android.test.runner" /> + <activity android:name="android.perftests.utils.PerfTestActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.perftests.permission.PERFTEST" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="android.perftests.permission"/> + +</manifest> diff --git a/apct-tests/perftests/permission/AndroidTest.xml b/apct-tests/perftests/permission/AndroidTest.xml new file mode 100644 index 000000000000..07558deafb6c --- /dev/null +++ b/apct-tests/perftests/permission/AndroidTest.xml @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<configuration description="Runs PermissionServicePerfTests metric instrumentation."> + <option name="test-suite-tag" value="apct"/> + <option name="test-suite-tag" value="apct-metric-instrumentation"/> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="test-file-name" value="PermissionServicePerfTests.apk"/> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true"/> + <option name="force-queryable" value="false"/> + <option name="test-file-name" value="UsePermissionApp0.apk"/> + <option name="test-file-name" value="UsePermissionApp1.apk"/> + <option name="test-file-name" value="UsePermissionApp2.apk"/> + <option name="test-file-name" value="UsePermissionApp3.apk"/> + <option name="test-file-name" value="UsePermissionApp4.apk"/> + <option name="test-file-name" value="UsePermissionApp5.apk"/> + <option name="test-file-name" value="UsePermissionApp6.apk"/> + <option name="test-file-name" value="UsePermissionApp7.apk"/> + <option name="test-file-name" value="UsePermissionApp8.apk"/> + <option name="test-file-name" value="UsePermissionApp9.apk"/> + <option name="test-file-name" value="UsePermissionApp10.apk"/> + <option name="test-file-name" value="UsePermissionApp11.apk"/> + <option name="test-file-name" value="UsePermissionApp12.apk"/> + <option name="test-file-name" value="UsePermissionApp13.apk"/> + <option name="test-file-name" value="UsePermissionApp14.apk"/> + <option name="test-file-name" value="UsePermissionApp15.apk"/> + <option name="test-file-name" value="UsePermissionApp16.apk"/> + <option name="test-file-name" value="UsePermissionApp17.apk"/> + <option name="test-file-name" value="UsePermissionApp18.apk"/> + <option name="test-file-name" value="UsePermissionApp19.apk"/> + <option name="test-file-name" value="UsePermissionApp20.apk"/> + <option name="test-file-name" value="UsePermissionApp21.apk"/> + <option name="test-file-name" value="UsePermissionApp22.apk"/> + <option name="test-file-name" value="UsePermissionApp23.apk"/> + <option name="test-file-name" value="UsePermissionApp24.apk"/> + <option name="test-file-name" value="UsePermissionApp25.apk"/> + <option name="test-file-name" value="UsePermissionApp26.apk"/> + <option name="test-file-name" value="UsePermissionApp27.apk"/> + <option name="test-file-name" value="UsePermissionApp28.apk"/> + <option name="test-file-name" value="UsePermissionApp29.apk"/> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="android.perftests.permission"/> + <option name="hidden-api-checks" value="false"/> + </test> + + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="directory-keys" value="/data/local/PermissionServicePerfTests"/> + <option name="collect-on-run-ended-only" value="true"/> + </metrics_collector> + + <!-- Needed for pushing the trace config file --> + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="push-file" key="trace_config_detailed.textproto" + value="/data/misc/perfetto-traces/trace_config.textproto"/> + <!--Install the content provider automatically when we push some file in sdcard folder.--> + <!--Needed to avoid the installation during the test suite.--> + <option name="push-file" key="trace_config_detailed.textproto" + value="/sdcard/sample.textproto"/> + <option name="push-file" key="UsePermissionApp0.apk" + value="/data/local/tmp/perftests/UsePermissionApp0.apk" /> + <option name="push-file" key="UsePermissionApp1.apk" + value="/data/local/tmp/perftests/UsePermissionApp1.apk" /> + <option name="push-file" key="UsePermissionApp2.apk" + value="/data/local/tmp/perftests/UsePermissionApp2.apk" /> + <option name="push-file" key="UsePermissionApp3.apk" + value="/data/local/tmp/perftests/UsePermissionApp3.apk" /> + <option name="push-file" key="UsePermissionApp4.apk" + value="/data/local/tmp/perftests/UsePermissionApp4.apk" /> + <option name="push-file" key="UsePermissionApp5.apk" + value="/data/local/tmp/perftests/UsePermissionApp5.apk" /> + <option name="push-file" key="UsePermissionApp6.apk" + value="/data/local/tmp/perftests/UsePermissionApp6.apk" /> + <option name="push-file" key="UsePermissionApp7.apk" + value="/data/local/tmp/perftests/UsePermissionApp7.apk" /> + <option name="push-file" key="UsePermissionApp8.apk" + value="/data/local/tmp/perftests/UsePermissionApp8.apk" /> + <option name="push-file" key="UsePermissionApp9.apk" + value="/data/local/tmp/perftests/UsePermissionApp9.apk" /> + <option name="push-file" key="UsePermissionApp10.apk" + value="/data/local/tmp/perftests/UsePermissionApp10.apk" /> + <option name="push-file" key="UsePermissionApp11.apk" + value="/data/local/tmp/perftests/UsePermissionApp11.apk" /> + <option name="push-file" key="UsePermissionApp12.apk" + value="/data/local/tmp/perftests/UsePermissionApp12.apk" /> + <option name="push-file" key="UsePermissionApp13.apk" + value="/data/local/tmp/perftests/UsePermissionApp13.apk" /> + <option name="push-file" key="UsePermissionApp14.apk" + value="/data/local/tmp/perftests/UsePermissionApp14.apk" /> + <option name="push-file" key="UsePermissionApp15.apk" + value="/data/local/tmp/perftests/UsePermissionApp15.apk" /> + <option name="push-file" key="UsePermissionApp16.apk" + value="/data/local/tmp/perftests/UsePermissionApp16.apk" /> + <option name="push-file" key="UsePermissionApp17.apk" + value="/data/local/tmp/perftests/UsePermissionApp17.apk" /> + <option name="push-file" key="UsePermissionApp18.apk" + value="/data/local/tmp/perftests/UsePermissionApp18.apk" /> + <option name="push-file" key="UsePermissionApp19.apk" + value="/data/local/tmp/perftests/UsePermissionApp19.apk" /> + <option name="push-file" key="UsePermissionApp20.apk" + value="/data/local/tmp/perftests/UsePermissionApp20.apk" /> + <option name="push-file" key="UsePermissionApp21.apk" + value="/data/local/tmp/perftests/UsePermissionApp21.apk" /> + <option name="push-file" key="UsePermissionApp22.apk" + value="/data/local/tmp/perftests/UsePermissionApp22.apk" /> + <option name="push-file" key="UsePermissionApp23.apk" + value="/data/local/tmp/perftests/UsePermissionApp23.apk" /> + <option name="push-file" key="UsePermissionApp24.apk" + value="/data/local/tmp/perftests/UsePermissionApp24.apk" /> + <option name="push-file" key="UsePermissionApp25.apk" + value="/data/local/tmp/perftests/UsePermissionApp25.apk" /> + <option name="push-file" key="UsePermissionApp26.apk" + value="/data/local/tmp/perftests/UsePermissionApp26.apk" /> + <option name="push-file" key="UsePermissionApp27.apk" + value="/data/local/tmp/perftests/UsePermissionApp27.apk" /> + <option name="push-file" key="UsePermissionApp28.apk" + value="/data/local/tmp/perftests/UsePermissionApp28.apk" /> + <option name="push-file" key="UsePermissionApp29.apk" + value="/data/local/tmp/perftests/UsePermissionApp29.apk" /> + </target_preparer> + + <!-- Needed for pulling the collected trace config on to the host --> + <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector"> + <option name="pull-pattern-keys" value="perfetto_file_path"/> + </metrics_collector> + + <!-- Needed for storing the perfetto trace files in the sdcard/test_results --> + <option name="isolated-storage" value="false"/> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="android.perftests.permission"/> + <option name="hidden-api-checks" value="false"/> + + <!-- Listener related args for collecting the traces and waiting for the device to + stabilize. --> + <option name="device-listeners" + value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener"/> + <!-- Guarantee that user defined RunListeners will be running before any of the default + listeners defined in this runner. --> + <option name="instrumentation-arg" key="newRunListenerMode" value="true"/> + + <!-- ProcLoadListener related arguments --> + <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting + the test run --> + <option name="instrumentation-arg" key="procload-collector:per_run" value="true"/> + <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3"/> + <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000"/> + <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000"/> + + <!-- PerfettoListener related arguments --> + <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true"/> + <option name="instrumentation-arg" key="perfetto_config_file" + value="trace_config.textproto"/> + + <!-- + PackageInstallerBenchmark will break for 5 minutes time out so it changes to 10 minutes + --> + <option name="test-timeout" value="600000" /> + </test> + + +</configuration> diff --git a/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp b/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp new file mode 100644 index 000000000000..1ad20b6fff6c --- /dev/null +++ b/apct-tests/perftests/permission/apps/usepermissionapp/Android.bp @@ -0,0 +1,232 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "UsePermissionApp0", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration0", + ], +} + +android_test_helper_app { + name: "UsePermissionApp1", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration1", + ], +} + +android_test_helper_app { + name: "UsePermissionApp2", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration2", + ], +} + +android_test_helper_app { + name: "UsePermissionApp3", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration3", + ], +} + +android_test_helper_app { + name: "UsePermissionApp4", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration4", + ], +} + +android_test_helper_app { + name: "UsePermissionApp5", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration5", + ], +} + +android_test_helper_app { + name: "UsePermissionApp6", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration6", + ], +} + +android_test_helper_app { + name: "UsePermissionApp7", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration7", + ], +} + +android_test_helper_app { + name: "UsePermissionApp8", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration8", + ], +} + +android_test_helper_app { + name: "UsePermissionApp9", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration9", + ], +} + +android_test_helper_app { + name: "UsePermissionApp10", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration10", + ], +} + +android_test_helper_app { + name: "UsePermissionApp11", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration11", + ], +} + +android_test_helper_app { + name: "UsePermissionApp12", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration12", + ], +} + +android_test_helper_app { + name: "UsePermissionApp13", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration13", + ], +} + +android_test_helper_app { + name: "UsePermissionApp14", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration14", + ], +} + +android_test_helper_app { + name: "UsePermissionApp15", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration15", + ], +} + +android_test_helper_app { + name: "UsePermissionApp16", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration16", + ], +} + +android_test_helper_app { + name: "UsePermissionApp17", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration17", + ], +} + +android_test_helper_app { + name: "UsePermissionApp18", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration18", + ], +} + +android_test_helper_app { + name: "UsePermissionApp19", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration19", + ], +} + +android_test_helper_app { + name: "UsePermissionApp20", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration20", + ], +} + +android_test_helper_app { + name: "UsePermissionApp21", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration21", + ], +} + +android_test_helper_app { + name: "UsePermissionApp22", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration22", + ], +} + +android_test_helper_app { + name: "UsePermissionApp23", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration23", + ], +} + +android_test_helper_app { + name: "UsePermissionApp24", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration24", + ], +} + +android_test_helper_app { + name: "UsePermissionApp25", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration25", + ], +} + +android_test_helper_app { + name: "UsePermissionApp26", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration26", + ], +} + +android_test_helper_app { + name: "UsePermissionApp27", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration27", + ], +} + +android_test_helper_app { + name: "UsePermissionApp28", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration28", + ], +} + +android_test_helper_app { + name: "UsePermissionApp29", + aaptflags: [ + "--rename-manifest-package android.perftests.appenumeration29", + ], +} diff --git a/apct-tests/perftests/permission/apps/usepermissionapp/AndroidManifest.xml b/apct-tests/perftests/permission/apps/usepermissionapp/AndroidManifest.xml new file mode 100644 index 000000000000..3bccefd24b49 --- /dev/null +++ b/apct-tests/perftests/permission/apps/usepermissionapp/AndroidManifest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.perftests.appenumeration"> + + <uses-permission android:name="android.permission.RECORD_AUDIO"/> + <uses-permission android:name="android.permission.CAMERA"/> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> + <uses-permission android:name="android.permission.RECORD_BACKGROUND_AUDIO" /> + <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" /> + <uses-permission android:name="android.permission.BACKGROUND_CAMERA" /> + <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" /> + <uses-permission android:name="android.permission.BODY_SENSORS" /> + <uses-permission android:name="android.permission.USE_BIOMETRIC" /> + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> + <uses-permission android:name="android.permission.SET_WALLPAPER" /> + <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" /> + + <queries> + <package android:name="android.perftests.appenumeration0" /> + <package android:name="android.perftests.appenumeration1" /> + <package android:name="android.perftests.appenumeration2" /> + <package android:name="android.perftests.appenumeration3" /> + <package android:name="android.perftests.appenumeration4" /> + <package android:name="android.perftests.appenumeration5" /> + <package android:name="android.perftests.appenumeration6" /> + <package android:name="android.perftests.appenumeration7" /> + <package android:name="android.perftests.appenumeration8" /> + <package android:name="android.perftests.appenumeration9" /> + <package android:name="android.perftests.appenumeration10" /> + <package android:name="android.perftests.appenumeration11" /> + <package android:name="android.perftests.appenumeration12" /> + <package android:name="android.perftests.appenumeration13" /> + <package android:name="android.perftests.appenumeration14" /> + <package android:name="android.perftests.appenumeration15" /> + <package android:name="android.perftests.appenumeration16" /> + <package android:name="android.perftests.appenumeration17" /> + <package android:name="android.perftests.appenumeration18" /> + <package android:name="android.perftests.appenumeration19" /> + <package android:name="android.perftests.appenumeration20" /> + <package android:name="android.perftests.appenumeration21" /> + <package android:name="android.perftests.appenumeration22" /> + <package android:name="android.perftests.appenumeration23" /> + <package android:name="android.perftests.appenumeration24" /> + <package android:name="android.perftests.appenumeration25" /> + <package android:name="android.perftests.appenumeration26" /> + <package android:name="android.perftests.appenumeration27" /> + <package android:name="android.perftests.appenumeration28" /> + <package android:name="android.perftests.appenumeration29" /> + </queries> + + <application android:hasCode="false" > + <activity android:name="android.perftests.utils.PerfTestActivity" + android:exported="true"> + <intent-filter> + <action android:name="android.perftests.permission.PERFTEST" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt b/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt new file mode 100644 index 000000000000..13e67e34a8d9 --- /dev/null +++ b/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2023 The Android Open 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.perftests.permission + +import android.Manifest +import android.os.ParcelFileDescriptor +import android.os.Trace +import android.perftests.utils.PerfManualStatusReporter +import android.perftests.utils.TraceMarkParser +import android.util.Log +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.compatibility.common.util.AdoptShellPermissionsRule +import com.android.compatibility.common.util.SystemUtil.eventually +import com.android.compatibility.common.util.SystemUtil.runShellCommand +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader +import java.util.concurrent.TimeUnit +import java.util.function.BiConsumer + +@RunWith(AndroidJUnit4::class) +class PermissionServicePerfTest { + @get:Rule val mPerfManualStatusReporter = PerfManualStatusReporter() + @get:Rule val mAdoptShellPermissionsRule = AdoptShellPermissionsRule( + InstrumentationRegistry.getInstrumentation().getUiAutomation(), + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES + ) + val mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation() + + @Test + fun testInstallPackages() { + mUiAutomation.executeShellCommand(COMMAND_TRACE_START) + eventually { assertThat(Trace.isTagEnabled(TRACE_TAG)).isTrue() } + val benchmarkState = mPerfManualStatusReporter.benchmarkState + val durations = ArrayList<Long>() + + while (benchmarkState.keepRunning(durations)) { + uninstallAllTestApps() + installAllTestApps() + + val parser = TraceMarkParser { line -> line.name.contains(PKG_INSTALL_TRACE_PREFIX) } + dumpResult(parser) { _, slices -> + slices.forEachIndexed { _, slice -> + durations.add(TimeUnit.MICROSECONDS.toNanos(slice.durationInMicroseconds)) + } + } + } + + mUiAutomation.executeShellCommand(COMMAND_TRACE_END) + } + + private fun installAllTestApps() { + for (i in 0..29) { + installTestApp(i) + } + } + + private fun installTestApp(appId: Int) { + val apkPath = "$APK_DIR$APK_NAME$appId.apk" + runShellCommand("pm install -t $apkPath") + } + + private fun uninstallAllTestApps() { + for (i in 0..29) { + uninstallTestApp(i) + } + } + + private fun uninstallTestApp(appId: Int) { + val packageName = "$PKG_NAME$appId" + runShellCommand("pm uninstall $packageName") + } + + private fun dumpResult( + parser: TraceMarkParser, + handler: BiConsumer<String, List<TraceMarkParser.TraceMarkSlice>> + ) { + parser.reset() + try { + val inputStream = ParcelFileDescriptor.AutoCloseInputStream( + mUiAutomation.executeShellCommand(COMMAND_TRACE_DUMP) + ) + val reader = BufferedReader(InputStreamReader(inputStream)) + var line = reader.readLine() + while (line != null) { + parser.visit(line) + line = reader.readLine() + } + } catch (e: IOException) { + Log.e(LOG_TAG, "IO error while reading trace dump file.") + } + parser.forAllSlices(handler) + } + + companion object { + private val LOG_TAG = PermissionServicePerfTest::class.java.simpleName + private const val TRACE_TAG = Trace.TRACE_TAG_PACKAGE_MANAGER + private const val PKG_INSTALL_TRACE_PREFIX = + "TaggedTracingPermissionManagerServiceImpl#onPackageInstalled" + private const val COMMAND_TRACE_START = "atrace --async_start -b 16000 pm" + private const val COMMAND_TRACE_END = "atrace --async_stop" + private const val COMMAND_TRACE_DUMP = "atrace --async_dump" + private const val APK_DIR = "/data/local/tmp/perftests/" + private const val APK_NAME = "UsePermissionApp" + private const val PKG_NAME = "android.perftests.appenumeration" + } +} 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 d940e380fa7e..b0f378d1752d 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -159,6 +159,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; @@ -513,6 +514,10 @@ public class JobSchedulerService extends com.android.server.SystemService if (name == null) { continue; } + if (DEBUG) { + Slog.d(TAG, "DeviceConfig " + name + + " changed to " + properties.getString(name, null)); + } switch (name) { case Constants.KEY_ENABLE_API_QUOTAS: case Constants.KEY_ENABLE_EXECUTION_SAFEGUARDS_UDC: @@ -3507,7 +3512,10 @@ public class JobSchedulerService extends com.android.server.SystemService } final boolean shouldForceBatchJob; - if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) { + if (job.overrideState > JobStatus.OVERRIDE_NONE) { + // The job should run for some test. Don't force batch it. + shouldForceBatchJob = false; + } else if (job.shouldTreatAsExpeditedJob() || job.shouldTreatAsUserInitiatedJob()) { // Never batch expedited or user-initiated jobs, even for RESTRICTED apps. shouldForceBatchJob = false; } else if (job.getEffectiveStandbyBucket() == RESTRICTED_INDEX) { @@ -4960,6 +4968,8 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "executeRunCommand(): " + pkgName + "/" + namespace + "/" + userId + " " + jobId + " s=" + satisfied + " f=" + force); + final CountDownLatch delayLatch = new CountDownLatch(1); + final JobStatus js; try { final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM); @@ -4968,7 +4978,7 @@ public class JobSchedulerService extends com.android.server.SystemService } synchronized (mLock) { - final JobStatus js = mJobs.getJobByUidAndJobId(uid, namespace, jobId); + js = mJobs.getJobByUidAndJobId(uid, namespace, jobId); if (js == null) { return JobSchedulerShellCommand.CMD_ERR_NO_JOB; } @@ -4979,23 +4989,71 @@ public class JobSchedulerService extends com.android.server.SystemService // Re-evaluate constraints after the override is set in case one of the overridden // constraints was preventing another constraint from thinking it needed to update. for (int c = mControllers.size() - 1; c >= 0; --c) { - mControllers.get(c).reevaluateStateLocked(uid); + mControllers.get(c).evaluateStateLocked(js); } if (!js.isConstraintsSatisfied()) { - js.overrideState = JobStatus.OVERRIDE_NONE; - return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS; + if (js.hasConnectivityConstraint() + && !js.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY) + && js.wouldBeReadyWithConstraint(JobStatus.CONSTRAINT_CONNECTIVITY)) { + // Because of how asynchronous the connectivity signals are, JobScheduler + // may not get the connectivity satisfaction signal immediately. In this + // case, wait a few seconds to see if it comes in before saying the + // connectivity constraint isn't satisfied. + mHandler.postDelayed( + checkConstraintRunnableForTesting( + mHandler, js, delayLatch, 5, 1000), + 1000); + } else { + // There's no asynchronous signal to wait for. We can immediately say the + // job's constraints aren't satisfied and return. + js.overrideState = JobStatus.OVERRIDE_NONE; + return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS; + } + } else { + delayLatch.countDown(); } - - queueReadyJobsForExecutionLocked(); - maybeRunPendingJobsLocked(); } } catch (RemoteException e) { // can't happen + return 0; + } + + // Choose to block the return until we're sure about the state of the connectivity job + // so that tests can expect a reliable state after calling the run command. + try { + delayLatch.await(7L, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "Couldn't wait for asynchronous constraint change", e); + } + + synchronized (mLock) { + if (!js.isConstraintsSatisfied()) { + js.overrideState = JobStatus.OVERRIDE_NONE; + return JobSchedulerShellCommand.CMD_ERR_CONSTRAINTS; + } + + queueReadyJobsForExecutionLocked(); + maybeRunPendingJobsLocked(); } return 0; } + private static Runnable checkConstraintRunnableForTesting(@NonNull final Handler handler, + @NonNull final JobStatus js, @NonNull final CountDownLatch latch, + final int remainingAttempts, final long delayMs) { + return () -> { + if (remainingAttempts <= 0 || js.isConstraintsSatisfied()) { + latch.countDown(); + return; + } + handler.postDelayed( + checkConstraintRunnableForTesting( + handler, js, latch, remainingAttempts - 1, delayMs), + delayMs); + }; + } + // Shell command infrastructure: immediately timeout currently executing jobs int executeStopCommand(PrintWriter pw, String pkgName, int userId, @Nullable String namespace, boolean hasJobId, int jobId, diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index bdc2246475d6..d39863c85f33 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -2192,7 +2192,7 @@ public final class JobStatus { * @return Whether or not this job would be ready to run if it had the specified constraint * granted, based on its requirements. */ - boolean wouldBeReadyWithConstraint(int constraint) { + public boolean wouldBeReadyWithConstraint(int constraint) { return readinessStatusWithConstraint(constraint, true); } diff --git a/api/Android.bp b/api/Android.bp index 363197a54fac..1686943d08ca 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -444,3 +444,12 @@ genrule { targets: ["droid"], }, } + +phony_rule { + name: "checkapi", + phony_deps: [ + "frameworks-base-api-current-compat", + "frameworks-base-api-system-current-compat", + "frameworks-base-api-module-lib-current-compat", + ], +} diff --git a/api/Android.mk b/api/Android.mk deleted file mode 100644 index ce5f995033c5..000000000000 --- a/api/Android.mk +++ /dev/null @@ -1,2 +0,0 @@ -.PHONY: checkapi -checkapi: frameworks-base-api-current-compat frameworks-base-api-system-current-compat frameworks-base-api-module-lib-current-compat diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index bcfb68ffd04d..7ae3224e7500 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -63,6 +63,7 @@ stubs_defaults { ":framework-graphics-srcs", ":framework-mediaprovider-sources", ":framework-nearby-sources", + ":framework-nfc-updatable-sources", ":framework-ondevicepersonalization-sources", ":framework-permission-sources", ":framework-permission-s-sources", @@ -183,6 +184,7 @@ doc_defaults { "-federationapi AndroidX $(location :current-androidx-api)", // doclava contains checks for a few issues that are have been migrated to metalava. // disable them in doclava, to avoid mistriggering or double triggering. + "-hide 101", // TODO: turn Lint 101 back into an error again "-hide 111", // HIDDEN_SUPERCLASS "-hide 113", // DEPRECATION_MISMATCH "-hide 125", // REQUIRES_PERMISSION diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp index ef1fa6097056..74344cd4b5a5 100644 --- a/api/StubLibraries.bp +++ b/api/StubLibraries.bp @@ -635,7 +635,6 @@ java_defaults { api_contributions: [ "framework-virtualization.stubs.source.test.api.contribution", "framework-location.stubs.source.test.api.contribution", - "framework-nfc.stubs.source.test.api.contribution", ], } diff --git a/api/api.go b/api/api.go index 2668999c572e..b975c55c5af9 100644 --- a/api/api.go +++ b/api/api.go @@ -31,7 +31,6 @@ const conscrypt = "conscrypt.module.public.api" const i18n = "i18n.module.public.api" const virtualization = "framework-virtualization" const location = "framework-location" -const nfc = "framework-nfc" var core_libraries_modules = []string{art, conscrypt, i18n} @@ -43,7 +42,7 @@ var core_libraries_modules = []string{art, conscrypt, i18n} // APIs. // In addition, the modules in this list are allowed to contribute to test APIs // stubs. -var non_updatable_modules = []string{virtualization, location, nfc} +var non_updatable_modules = []string{virtualization, location} // The intention behind this soong plugin is to generate a number of "merged" // API-related modules that would otherwise require a large amount of very @@ -64,6 +63,7 @@ type CombinedApisProperties struct { type CombinedApis struct { android.ModuleBase + android.DefaultableModuleBase properties CombinedApisProperties } @@ -74,6 +74,7 @@ func init() { func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory) + ctx.RegisterModuleType("combined_apis_defaults", CombinedApisModuleDefaultsFactory) } var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents) @@ -409,6 +410,7 @@ func combinedApisModuleFactory() android.Module { module := &CombinedApis{} module.AddProperties(&module.properties) android.InitAndroidModule(module) + android.InitDefaultableModule(module) android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) }) return module } @@ -445,3 +447,16 @@ func remove(s []string, v string) []string { } return s2 } + +// Defaults +type CombinedApisModuleDefaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +func CombinedApisModuleDefaultsFactory() android.Module { + module := &CombinedApisModuleDefaults{} + module.AddProperties(&CombinedApisProperties{}) + android.InitDefaultsModule(module) + return module +} diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md index e7361fe95e8e..b6e4e0de8cf7 100644 --- a/cmds/uinput/README.md +++ b/cmds/uinput/README.md @@ -7,11 +7,23 @@ There are two ways to use the `uinput` command: or app (such as the CTS tests via [`UinputDevice`][UinputDevice]). * `uinput <filename>` reads commands from a file instead of standard input. +There are also two supported input formats, described in the sections below. The tool will +automatically detect which format is being used. + [UinputDevice]: https://cs.android.com/android/platform/superproject/main/+/main:cts/libs/input/src/com/android/cts/input/UinputDevice.java -## Command format +## evemu recording format (recommended) + +`uinput` supports the evemu format, as used by the [FreeDesktop project's evemu suite][FreeDesktop]. +This is a simple text-based format compatible with recording and replay tools on other platforms. +However, it only supports playback of events from one device from a single recording. Recordings can +be made using the `evemu-record` command on Android or other Linux-based OSes. + +[FreeDesktop]: https://gitlab.freedesktop.org/libevdev/evemu + +## JSON-like format -Input commands should be in JSON format, though the parser is in [lenient mode] to allow comments, +The other supported format is JSON-based, though the parser is in [lenient mode] to allow comments, and integers can be specified in hexadecimal (e.g. `0xABCD`). The input file (or standard input) can contain multiple commands, which will be executed in sequence. Simply add multiple JSON objects to the file, one after the other without separators: @@ -34,9 +46,9 @@ Many examples of command files can be found [in the CTS tests][cts-example-jsons [lenient mode]: https://developer.android.com/reference/android/util/JsonReader#setLenient(boolean) [cts-example-jsons]: https://cs.android.com/android/platform/superproject/main/+/main:cts/tests/tests/hardware/res/raw/ -## Command reference +### Command reference -### `register` +#### `register` Register a new uinput device @@ -122,7 +134,7 @@ Example: [struct input_absinfo]: https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/kernel/uapi/linux/input.h?q=%22struct%20input_absinfo%22 -#### Waiting for registration +##### Waiting for registration After the command is sent, there will be a delay before the device is set up by the Android input stack, and `uinput` does not wait for that process to finish. Any commands sent to the device during @@ -135,12 +147,12 @@ finished processing. [onInputDeviceAdded]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html -#### Unregistering the device +##### Unregistering the device As soon as EOF is reached (either in interactive mode, or in file mode), the device that was created will be unregistered. There is no explicit command for unregistering a device. -### `delay` +#### `delay` Add a delay to command processing @@ -160,7 +172,7 @@ Example: } ``` -### `inject` +#### `inject` Send an array of uinput event packets to the uinput device @@ -190,7 +202,7 @@ keys would look like this: } ``` -### `sync` +#### `sync` A command used to get a response once the command is processed. When several `inject` and `delay` commands are used in a row, the `sync` command can be used to track the progress of the command diff --git a/core/api/current.txt b/core/api/current.txt index 7ff54f286912..46c8f8208883 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -49,6 +49,7 @@ package android { field public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE"; field public static final String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE"; field public static final String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE"; + field @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public static final String BIND_TV_AD_SERVICE = "android.permission.BIND_TV_AD_SERVICE"; field public static final String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT"; field public static final String BIND_TV_INTERACTIVE_APP = "android.permission.BIND_TV_INTERACTIVE_APP"; field public static final String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"; @@ -1601,6 +1602,7 @@ package android { field public static final int switchTextOff = 16843628; // 0x101036c field public static final int switchTextOn = 16843627; // 0x101036b field public static final int syncable = 16842777; // 0x1010019 + field @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") public static final int systemUserOnly; field public static final int tabStripEnabled = 16843453; // 0x10102bd field public static final int tabStripLeft = 16843451; // 0x10102bb field public static final int tabStripRight = 16843452; // 0x10102bc @@ -4370,7 +4372,7 @@ package android.app { method public final android.media.session.MediaController getMediaController(); method @NonNull public android.view.MenuInflater getMenuInflater(); method @NonNull public android.window.OnBackInvokedDispatcher getOnBackInvokedDispatcher(); - method @Deprecated public final android.app.Activity getParent(); + method public final android.app.Activity getParent(); method @Nullable public android.content.Intent getParentActivityIntent(); method public android.content.SharedPreferences getPreferences(int); method @Nullable public android.net.Uri getReferrer(); @@ -4388,7 +4390,7 @@ package android.app { method public void invalidateOptionsMenu(); method public boolean isActivityTransitionRunning(); method public boolean isChangingConfigurations(); - method @Deprecated public final boolean isChild(); + method public final boolean isChild(); method public boolean isDestroyed(); method public boolean isFinishing(); method public boolean isImmersive(); @@ -9484,12 +9486,15 @@ package android.appwidget { method @NonNull public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForPackage(@NonNull String, @Nullable android.os.UserHandle); method @NonNull public java.util.List<android.appwidget.AppWidgetProviderInfo> getInstalledProvidersForProfile(@Nullable android.os.UserHandle); method public static android.appwidget.AppWidgetManager getInstance(android.content.Context); + method @FlaggedApi("android.appwidget.flags.generated_previews") @Nullable public android.widget.RemoteViews getWidgetPreview(@NonNull android.content.ComponentName, @Nullable android.os.UserHandle, int); method public boolean isRequestPinAppWidgetSupported(); method @Deprecated public void notifyAppWidgetViewDataChanged(int[], int); method @Deprecated public void notifyAppWidgetViewDataChanged(int, int); method public void partiallyUpdateAppWidget(int[], android.widget.RemoteViews); method public void partiallyUpdateAppWidget(int, android.widget.RemoteViews); + method @FlaggedApi("android.appwidget.flags.generated_previews") public void removeWidgetPreview(@NonNull android.content.ComponentName, int); method public boolean requestPinAppWidget(@NonNull android.content.ComponentName, @Nullable android.os.Bundle, @Nullable android.app.PendingIntent); + method @FlaggedApi("android.appwidget.flags.generated_previews") public void setWidgetPreview(@NonNull android.content.ComponentName, int, @NonNull android.widget.RemoteViews); method public void updateAppWidget(int[], android.widget.RemoteViews); method public void updateAppWidget(int, android.widget.RemoteViews); method public void updateAppWidget(android.content.ComponentName, android.widget.RemoteViews); @@ -9563,6 +9568,7 @@ package android.appwidget { field public int autoAdvanceViewId; field public android.content.ComponentName configure; field @IdRes public int descriptionRes; + field @FlaggedApi("android.appwidget.flags.generated_previews") public int generatedPreviewCategories; field public int icon; field public int initialKeyguardLayout; field public int initialLayout; @@ -18674,6 +18680,7 @@ package android.hardware.biometrics { method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public void authenticate(@NonNull android.hardware.biometrics.BiometricPrompt.CryptoObject, @NonNull android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.biometrics.BiometricPrompt.AuthenticationCallback); method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public void authenticate(@NonNull android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.biometrics.BiometricPrompt.AuthenticationCallback); method @Nullable public int getAllowedAuthenticators(); + method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @Nullable public android.hardware.biometrics.PromptContentView getContentView(); method @Nullable public CharSequence getDescription(); method @Nullable public CharSequence getNegativeButtonText(); method @Nullable public CharSequence getSubtitle(); @@ -18721,6 +18728,7 @@ package android.hardware.biometrics { method @NonNull public android.hardware.biometrics.BiometricPrompt build(); method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setAllowedAuthenticators(int); method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setConfirmationRequired(boolean); + method @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setContentView(@NonNull android.hardware.biometrics.PromptContentView); method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence); method @Deprecated @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setDeviceCredentialAllowed(boolean); method @NonNull public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener); @@ -18744,6 +18752,43 @@ package android.hardware.biometrics { method @Nullable public java.security.Signature getSignature(); } + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public interface PromptContentListItem { + } + + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public final class PromptContentListItemBulletedText implements android.os.Parcelable android.hardware.biometrics.PromptContentListItem { + ctor public PromptContentListItemBulletedText(@NonNull CharSequence); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.biometrics.PromptContentListItemBulletedText> CREATOR; + } + + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public final class PromptContentListItemPlainText implements android.os.Parcelable android.hardware.biometrics.PromptContentListItem { + ctor public PromptContentListItemPlainText(@NonNull CharSequence); + method public int describeContents(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.biometrics.PromptContentListItemPlainText> CREATOR; + } + + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public interface PromptContentView { + } + + @FlaggedApi("android.hardware.biometrics.custom_biometric_prompt") public final class PromptVerticalListContentView implements android.os.Parcelable android.hardware.biometrics.PromptContentView { + method public int describeContents(); + method @Nullable public CharSequence getDescription(); + method @NonNull public java.util.List<android.hardware.biometrics.PromptContentListItem> getListItems(); + method public static int getMaxEachItemCharacterNumber(); + method public static int getMaxItemCount(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.biometrics.PromptVerticalListContentView> CREATOR; + } + + public static final class PromptVerticalListContentView.Builder { + ctor public PromptVerticalListContentView.Builder(); + method @NonNull public android.hardware.biometrics.PromptVerticalListContentView.Builder addListItem(@NonNull android.hardware.biometrics.PromptContentListItem); + method @NonNull public android.hardware.biometrics.PromptVerticalListContentView build(); + method @NonNull public android.hardware.biometrics.PromptVerticalListContentView.Builder setDescription(@NonNull CharSequence); + } + } package android.hardware.camera2 { @@ -19733,7 +19778,7 @@ package android.hardware.camera2.params { @FlaggedApi("com.android.internal.camera.flags.concert_mode") public final class LensIntrinsicsSample { ctor @FlaggedApi("com.android.internal.camera.flags.concert_mode") public LensIntrinsicsSample(long, @NonNull float[]); method @FlaggedApi("com.android.internal.camera.flags.concert_mode") @NonNull public float[] getLensIntrinsics(); - method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getTimestamp(); + method @FlaggedApi("com.android.internal.camera.flags.concert_mode") public long getTimestampNanos(); } public final class LensShadingMap { @@ -28747,460 +28792,6 @@ package android.net.vcn { } -package android.nfc { - - public final class AvailableNfcAntenna implements android.os.Parcelable { - ctor public AvailableNfcAntenna(int, int); - method public int describeContents(); - method public int getLocationX(); - method public int getLocationY(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR; - } - - public class FormatException extends java.lang.Exception { - ctor public FormatException(); - ctor public FormatException(String); - ctor public FormatException(String, Throwable); - } - - public final class NdefMessage implements android.os.Parcelable { - ctor public NdefMessage(byte[]) throws android.nfc.FormatException; - ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...); - ctor public NdefMessage(android.nfc.NdefRecord[]); - method public int describeContents(); - method public int getByteArrayLength(); - method public android.nfc.NdefRecord[] getRecords(); - method public byte[] toByteArray(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefMessage> CREATOR; - } - - public final class NdefRecord implements android.os.Parcelable { - ctor public NdefRecord(short, byte[], byte[], byte[]); - ctor @Deprecated public NdefRecord(byte[]) throws android.nfc.FormatException; - method public static android.nfc.NdefRecord createApplicationRecord(String); - method public static android.nfc.NdefRecord createExternal(String, String, byte[]); - method public static android.nfc.NdefRecord createMime(String, byte[]); - method public static android.nfc.NdefRecord createTextRecord(String, String); - method public static android.nfc.NdefRecord createUri(android.net.Uri); - method public static android.nfc.NdefRecord createUri(String); - method public int describeContents(); - method public byte[] getId(); - method public byte[] getPayload(); - method public short getTnf(); - method public byte[] getType(); - method @Deprecated public byte[] toByteArray(); - method public String toMimeType(); - method public android.net.Uri toUri(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR; - field public static final byte[] RTD_ALTERNATIVE_CARRIER; - field public static final byte[] RTD_HANDOVER_CARRIER; - field public static final byte[] RTD_HANDOVER_REQUEST; - field public static final byte[] RTD_HANDOVER_SELECT; - field public static final byte[] RTD_SMART_POSTER; - field public static final byte[] RTD_TEXT; - field public static final byte[] RTD_URI; - field public static final short TNF_ABSOLUTE_URI = 3; // 0x3 - field public static final short TNF_EMPTY = 0; // 0x0 - field public static final short TNF_EXTERNAL_TYPE = 4; // 0x4 - field public static final short TNF_MIME_MEDIA = 2; // 0x2 - field public static final short TNF_UNCHANGED = 6; // 0x6 - field public static final short TNF_UNKNOWN = 5; // 0x5 - field public static final short TNF_WELL_KNOWN = 1; // 0x1 - } - - public final class NfcAdapter { - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean allowTransaction(); - method public void disableForegroundDispatch(android.app.Activity); - method public void disableReaderMode(android.app.Activity); - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean disallowTransaction(); - method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]); - method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); - method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); - method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo(); - method @FlaggedApi("android.nfc.enable_nfc_charging") @Nullable public android.nfc.WlcLDeviceInfo getWlcLDeviceInfo(); - method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler); - method public boolean isEnabled(); - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported(); - method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled(); - method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported(); - method public boolean isSecureNfcEnabled(); - method public boolean isSecureNfcSupported(); - method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled(); - method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity); - method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int); - field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED"; - field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; - field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED"; - field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; - field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; - field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED"; - field public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE"; - field public static final String EXTRA_AID = "android.nfc.extra.AID"; - field public static final String EXTRA_DATA = "android.nfc.extra.DATA"; - field public static final String EXTRA_ID = "android.nfc.extra.ID"; - field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; - field public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON"; - field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; - field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME"; - field public static final String EXTRA_TAG = "android.nfc.extra.TAG"; - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_DISABLE = 0; // 0x0 - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_KEEP = -1; // 0xffffffff - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_A = 1; // 0x1 - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_B = 2; // 0x2 - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_F = 4; // 0x4 - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_DISABLE = 0; // 0x0 - field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_KEEP = -1; // 0xffffffff - field public static final int FLAG_READER_NFC_A = 1; // 0x1 - field public static final int FLAG_READER_NFC_B = 2; // 0x2 - field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10 - field public static final int FLAG_READER_NFC_F = 4; // 0x4 - field public static final int FLAG_READER_NFC_V = 8; // 0x8 - field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100 - field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80 - field public static final int PREFERRED_PAYMENT_CHANGED = 2; // 0x2 - field public static final int PREFERRED_PAYMENT_LOADED = 1; // 0x1 - field public static final int PREFERRED_PAYMENT_UPDATED = 3; // 0x3 - field public static final int STATE_OFF = 1; // 0x1 - field public static final int STATE_ON = 3; // 0x3 - field public static final int STATE_TURNING_OFF = 4; // 0x4 - field public static final int STATE_TURNING_ON = 2; // 0x2 - } - - @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback { - method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent); - } - - @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback { - method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent); - } - - @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback { - method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent); - } - - public static interface NfcAdapter.OnTagRemovedListener { - method public void onTagRemoved(); - } - - public static interface NfcAdapter.ReaderCallback { - method public void onTagDiscovered(android.nfc.Tag); - } - - public final class NfcAntennaInfo implements android.os.Parcelable { - ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>); - method public int describeContents(); - method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas(); - method public int getDeviceHeight(); - method public int getDeviceWidth(); - method public boolean isDeviceFoldable(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR; - } - - public final class NfcEvent { - field public final android.nfc.NfcAdapter nfcAdapter; - field public final int peerLlcpMajorVersion; - field public final int peerLlcpMinorVersion; - } - - public final class NfcManager { - method public android.nfc.NfcAdapter getDefaultAdapter(); - } - - public final class Tag implements android.os.Parcelable { - method public int describeContents(); - method public byte[] getId(); - method public String[] getTechList(); - method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR; - } - - public class TagLostException extends java.io.IOException { - ctor public TagLostException(); - ctor public TagLostException(String); - } - - @FlaggedApi("android.nfc.enable_nfc_charging") public final class WlcLDeviceInfo implements android.os.Parcelable { - ctor public WlcLDeviceInfo(double, double, double, int); - method public int describeContents(); - method public double getBatteryLevel(); - method public double getProductId(); - method public int getState(); - method public double getTemperature(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field public static final int CONNECTED_CHARGING = 2; // 0x2 - field public static final int CONNECTED_DISCHARGING = 3; // 0x3 - field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcLDeviceInfo> CREATOR; - field public static final int DISCONNECTED = 1; // 0x1 - } - -} - -package android.nfc.cardemulation { - - public final class CardEmulation { - method public boolean categoryAllowsForegroundPreference(String); - method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService(); - method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String); - method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService(); - method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter); - method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService(); - method public int getSelectionModeForCategory(String); - method public boolean isDefaultServiceForAid(android.content.ComponentName, String); - method public boolean isDefaultServiceForCategory(android.content.ComponentName, String); - method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>); - method public boolean removeAidsForService(android.content.ComponentName, String); - method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String); - method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean); - method public boolean supportsAidPrefixRegistration(); - method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName); - method public boolean unsetPreferredService(android.app.Activity); - field public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; - field public static final String CATEGORY_OTHER = "other"; - field public static final String CATEGORY_PAYMENT = "payment"; - field public static final String EXTRA_CATEGORY = "category"; - field public static final String EXTRA_SERVICE_COMPONENT = "component"; - field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1 - field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2 - field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0 - } - - public abstract class HostApduService extends android.app.Service { - ctor public HostApduService(); - method public final void notifyUnhandled(); - method public final android.os.IBinder onBind(android.content.Intent); - method public abstract void onDeactivated(int); - method public abstract byte[] processCommandApdu(byte[], android.os.Bundle); - method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>); - method public final void sendResponseApdu(byte[]); - field public static final int DEACTIVATION_DESELECTED = 1; // 0x1 - field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0 - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA"; - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN"; - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP"; - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A' - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B' - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F' - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE"; - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X' - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O' - field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U' - field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE"; - field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service"; - } - - public abstract class HostNfcFService extends android.app.Service { - ctor public HostNfcFService(); - method public final android.os.IBinder onBind(android.content.Intent); - method public abstract void onDeactivated(int); - method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle); - method public final void sendResponsePacket(byte[]); - field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0 - field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE"; - field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service"; - } - - public final class NfcFCardEmulation { - method public boolean disableService(android.app.Activity) throws java.lang.RuntimeException; - method public boolean enableService(android.app.Activity, android.content.ComponentName) throws java.lang.RuntimeException; - method public static android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter); - method public String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException; - method public String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException; - method public boolean registerSystemCodeForService(android.content.ComponentName, String) throws java.lang.RuntimeException; - method public boolean setNfcid2ForService(android.content.ComponentName, String) throws java.lang.RuntimeException; - method public boolean unregisterSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException; - } - - public abstract class OffHostApduService extends android.app.Service { - ctor public OffHostApduService(); - field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"; - field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service"; - } - -} - -package android.nfc.tech { - - public final class IsoDep implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.IsoDep get(android.nfc.Tag); - method public byte[] getHiLayerResponse(); - method public byte[] getHistoricalBytes(); - method public int getMaxTransceiveLength(); - method public android.nfc.Tag getTag(); - method public int getTimeout(); - method public boolean isConnected(); - method public boolean isExtendedLengthApduSupported(); - method public void setTimeout(int); - method public byte[] transceive(byte[]) throws java.io.IOException; - } - - public final class MifareClassic implements android.nfc.tech.TagTechnology { - method public boolean authenticateSectorWithKeyA(int, byte[]) throws java.io.IOException; - method public boolean authenticateSectorWithKeyB(int, byte[]) throws java.io.IOException; - method public int blockToSector(int); - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public void decrement(int, int) throws java.io.IOException; - method public static android.nfc.tech.MifareClassic get(android.nfc.Tag); - method public int getBlockCount(); - method public int getBlockCountInSector(int); - method public int getMaxTransceiveLength(); - method public int getSectorCount(); - method public int getSize(); - method public android.nfc.Tag getTag(); - method public int getTimeout(); - method public int getType(); - method public void increment(int, int) throws java.io.IOException; - method public boolean isConnected(); - method public byte[] readBlock(int) throws java.io.IOException; - method public void restore(int) throws java.io.IOException; - method public int sectorToBlock(int); - method public void setTimeout(int); - method public byte[] transceive(byte[]) throws java.io.IOException; - method public void transfer(int) throws java.io.IOException; - method public void writeBlock(int, byte[]) throws java.io.IOException; - field public static final int BLOCK_SIZE = 16; // 0x10 - field public static final byte[] KEY_DEFAULT; - field public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY; - field public static final byte[] KEY_NFC_FORUM; - field public static final int SIZE_1K = 1024; // 0x400 - field public static final int SIZE_2K = 2048; // 0x800 - field public static final int SIZE_4K = 4096; // 0x1000 - field public static final int SIZE_MINI = 320; // 0x140 - field public static final int TYPE_CLASSIC = 0; // 0x0 - field public static final int TYPE_PLUS = 1; // 0x1 - field public static final int TYPE_PRO = 2; // 0x2 - field public static final int TYPE_UNKNOWN = -1; // 0xffffffff - } - - public final class MifareUltralight implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag); - method public int getMaxTransceiveLength(); - method public android.nfc.Tag getTag(); - method public int getTimeout(); - method public int getType(); - method public boolean isConnected(); - method public byte[] readPages(int) throws java.io.IOException; - method public void setTimeout(int); - method public byte[] transceive(byte[]) throws java.io.IOException; - method public void writePage(int, byte[]) throws java.io.IOException; - field public static final int PAGE_SIZE = 4; // 0x4 - field public static final int TYPE_ULTRALIGHT = 1; // 0x1 - field public static final int TYPE_ULTRALIGHT_C = 2; // 0x2 - field public static final int TYPE_UNKNOWN = -1; // 0xffffffff - } - - public final class Ndef implements android.nfc.tech.TagTechnology { - method public boolean canMakeReadOnly(); - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.Ndef get(android.nfc.Tag); - method public android.nfc.NdefMessage getCachedNdefMessage(); - method public int getMaxSize(); - method public android.nfc.NdefMessage getNdefMessage() throws android.nfc.FormatException, java.io.IOException; - method public android.nfc.Tag getTag(); - method public String getType(); - method public boolean isConnected(); - method public boolean isWritable(); - method public boolean makeReadOnly() throws java.io.IOException; - method public void writeNdefMessage(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; - field public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic"; - field public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1"; - field public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2"; - field public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3"; - field public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4"; - } - - public final class NdefFormatable implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public void format(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; - method public void formatReadOnly(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; - method public static android.nfc.tech.NdefFormatable get(android.nfc.Tag); - method public android.nfc.Tag getTag(); - method public boolean isConnected(); - } - - public final class NfcA implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.NfcA get(android.nfc.Tag); - method public byte[] getAtqa(); - method public int getMaxTransceiveLength(); - method public short getSak(); - method public android.nfc.Tag getTag(); - method public int getTimeout(); - method public boolean isConnected(); - method public void setTimeout(int); - method public byte[] transceive(byte[]) throws java.io.IOException; - } - - public final class NfcB implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.NfcB get(android.nfc.Tag); - method public byte[] getApplicationData(); - method public int getMaxTransceiveLength(); - method public byte[] getProtocolInfo(); - method public android.nfc.Tag getTag(); - method public boolean isConnected(); - method public byte[] transceive(byte[]) throws java.io.IOException; - } - - public final class NfcBarcode implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.NfcBarcode get(android.nfc.Tag); - method public byte[] getBarcode(); - method public android.nfc.Tag getTag(); - method public int getType(); - method public boolean isConnected(); - field public static final int TYPE_KOVIO = 1; // 0x1 - field public static final int TYPE_UNKNOWN = -1; // 0xffffffff - } - - public final class NfcF implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.NfcF get(android.nfc.Tag); - method public byte[] getManufacturer(); - method public int getMaxTransceiveLength(); - method public byte[] getSystemCode(); - method public android.nfc.Tag getTag(); - method public int getTimeout(); - method public boolean isConnected(); - method public void setTimeout(int); - method public byte[] transceive(byte[]) throws java.io.IOException; - } - - public final class NfcV implements android.nfc.tech.TagTechnology { - method public void close() throws java.io.IOException; - method public void connect() throws java.io.IOException; - method public static android.nfc.tech.NfcV get(android.nfc.Tag); - method public byte getDsfId(); - method public int getMaxTransceiveLength(); - method public byte getResponseFlags(); - method public android.nfc.Tag getTag(); - method public boolean isConnected(); - method public byte[] transceive(byte[]) throws java.io.IOException; - } - - public interface TagTechnology extends java.io.Closeable { - method public void connect() throws java.io.IOException; - method public android.nfc.Tag getTag(); - method public boolean isConnected(); - } - -} - package android.opengl { public class EGL14 { @@ -33400,7 +32991,7 @@ package android.os { @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public final class PowerMonitorReadings { method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public long getConsumedEnergy(@NonNull android.os.PowerMonitor); - method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public long getTimestamp(@NonNull android.os.PowerMonitor); + method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public long getTimestampMillis(@NonNull android.os.PowerMonitor); field @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public static final int ENERGY_UNAVAILABLE = -1; // 0xffffffff } @@ -33410,6 +33001,7 @@ package android.os { method public static final long getElapsedCpuTime(); method public static final int[] getExclusiveCores(); method public static final int getGidForName(String); + method @FlaggedApi("com.android.sdksandbox.flags.sdk_sandbox_uid_to_app_uid_api") public static final int getSdkSandboxUidForAppUid(int); method public static long getStartElapsedRealtime(); method public static long getStartRequestedElapsedRealtime(); method public static long getStartRequestedUptimeMillis(); @@ -33911,7 +33503,6 @@ package android.os { @FlaggedApi("android.os.adpf_gpu_report_actual_work_duration") public final class WorkDuration implements android.os.Parcelable { ctor public WorkDuration(); - ctor public WorkDuration(long, long, long, long); method public int describeContents(); method public long getActualCpuDurationNanos(); method public long getActualGpuDurationNanos(); @@ -33994,8 +33585,8 @@ package android.os.health { } public class SystemHealthManager { - method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable android.os.Handler, @NonNull java.util.function.Consumer<android.os.PowerMonitorReadings>, @NonNull java.util.function.Consumer<java.lang.RuntimeException>); - method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable android.os.Handler, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>); + method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.PowerMonitorReadings,java.lang.RuntimeException>); + method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>); method public android.os.health.HealthStats takeMyUidSnapshot(); method public android.os.health.HealthStats takeUidSnapshot(int); method public android.os.health.HealthStats[] takeUidSnapshots(int[]); @@ -41550,6 +41141,8 @@ package android.speech { field public static final String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL"; field public static final String EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE"; field public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES = "android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES"; + field @FlaggedApi("android.speech.flags.multilang_extra_launch") public static final String EXTRA_LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS = "android.speech.extra.LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS"; + field @FlaggedApi("android.speech.flags.multilang_extra_launch") public static final String EXTRA_LANGUAGE_SWITCH_MAX_SWITCHES = "android.speech.extra.LANGUAGE_SWITCH_MAX_SWITCHES"; field public static final String EXTRA_MASK_OFFENSIVE_WORDS = "android.speech.extra.MASK_OFFENSIVE_WORDS"; field public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS"; field public static final String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE"; @@ -45341,7 +44934,7 @@ package android.telephony { method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid); method public boolean canManageSubscription(android.telephony.SubscriptionInfo); - method @FlaggedApi("com.android.internal.telephony.flags.work_profile_api_split") @NonNull public android.telephony.SubscriptionManager createForAllUserProfiles(); + method @FlaggedApi("com.android.internal.telephony.flags.enforce_subscription_user_filter") @NonNull public android.telephony.SubscriptionManager createForAllUserProfiles(); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>); method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context); method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList(); @@ -47293,6 +46886,7 @@ package android.text { method public int getLineForOffset(int); method public int getLineForVertical(int); method public float getLineLeft(int); + method @FlaggedApi("com.android.text.flags.inter_character_justification") @IntRange(from=0) public int getLineLetterSpacingUnitCount(@IntRange(from=0) int, boolean); method public float getLineMax(int); method public float getLineRight(int); method @FlaggedApi("com.android.text.flags.use_bounds_for_width") public final float getLineSpacingAmount(); @@ -51845,6 +51439,10 @@ package android.view { ctor public SurfaceControl.TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int); } + @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public interface SurfaceControlInputReceiver { + method public boolean onInputEvent(@NonNull android.view.InputEvent); + } + public class SurfaceControlViewHost { ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder); method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage(); @@ -53968,10 +53566,13 @@ package android.view { method @Deprecated public android.view.Display getDefaultDisplay(); method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics(); method public default boolean isCrossWindowBlurEnabled(); + method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver); method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>); + method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver); method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer); method public void removeViewImmediate(android.view.View); + method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.os.IBinder); method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>); field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE"; field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"; @@ -53984,6 +53585,8 @@ package android.view { field public static final String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE"; field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES = "android.window.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES"; field public static final String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS"; + field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"; + field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE"; field public static final String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS"; field public static final String PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION = "android.window.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION"; field @FlaggedApi("com.android.window.flags.supports_multi_instance_system_ui") public static final String PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI = "android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"; @@ -56498,6 +56101,7 @@ package android.view.textclassifier { field public static final String TYPE_EMAIL = "email"; field public static final String TYPE_FLIGHT_NUMBER = "flight"; field public static final String TYPE_OTHER = "other"; + field @FlaggedApi("android.service.notification.redact_sensitive_notifications_from_untrusted_listeners") public static final String TYPE_OTP_CODE = "otp_code"; field public static final String TYPE_PHONE = "phone"; field public static final String TYPE_UNKNOWN = ""; field public static final String TYPE_URL = "url"; diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt index f331e7f5fa84..162f54cc6d5a 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -181,12 +181,6 @@ BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSAB Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: - Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: - Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: - Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: @@ -715,86 +709,6 @@ RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean): Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.net.sip.SipAudioCall#startAudio(): Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): - Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): - Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): - Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): - Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): - Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): - Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): - Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): - Method 'decrement' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): - Method 'increment' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): - Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#restore(int): - Method 'restore' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): - Method 'transfer' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): - Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): - Method 'readPages' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): - Method 'writePage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): - Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#isWritable(): - Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): - Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): - Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): - Method 'format' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): - Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#close(): - Method 'close' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#connect(): - Method 'connect' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.BugreportManager#cancelBugreport(): Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.Build#getSerial(): diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index c1b9f64b9e8a..24b923326baa 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -319,11 +319,6 @@ package android.net.wifi { package android.nfc { - public class NfcFrameworkInitializer { - method public static void registerServiceWrappers(); - method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager); - } - public class NfcServiceManager { method @NonNull public android.nfc.NfcServiceManager.ServiceRegisterer getNfcManagerServiceRegisterer(); } diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt index a6a948c7f64c..a2179bc59707 100644 --- a/core/api/module-lib-lint-baseline.txt +++ b/core/api/module-lib-lint-baseline.txt @@ -235,14 +235,6 @@ BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS: Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: - Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: - Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: - Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: - Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: @@ -1009,86 +1001,6 @@ RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): - Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): - Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): - Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): - Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): - Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): - Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): - Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): - Method 'decrement' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): - Method 'increment' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): - Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#restore(int): - Method 'restore' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): - Method 'transfer' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): - Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): - Method 'readPages' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): - Method 'writePage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): - Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#isWritable(): - Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): - Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): - Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): - Method 'format' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): - Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#close(): - Method 'close' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#connect(): - Method 'connect' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.BugreportManager#cancelBugreport(): Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.BugreportManager#preDumpUiData(): @@ -1769,8 +1681,6 @@ SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE: Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) -SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: - Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: diff --git a/core/api/removed.txt b/core/api/removed.txt index b58c822e39bc..3c7c0d6e6ea1 100644 --- a/core/api/removed.txt +++ b/core/api/removed.txt @@ -190,22 +190,6 @@ package android.net { } -package android.nfc { - - public final class NfcAdapter { - method @Deprecated public void disableForegroundNdefPush(android.app.Activity); - method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage); - method @Deprecated public boolean invokeBeam(android.app.Activity); - method @Deprecated public boolean isNdefPushEnabled(); - method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity); - method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity); - method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...); - method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...); - method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...); - } - -} - package android.os { public class BatteryManager { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 506d2035c984..bd4ecf298d77 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -475,6 +475,7 @@ package android { field public static final int config_defaultNotes = 17039429; // 0x1040045 field @FlaggedApi("android.permission.flags.retail_demo_role_enabled") public static final int config_defaultRetailDemo; field public static final int config_defaultSms = 17039396; // 0x1040024 + field @FlaggedApi("android.permission.flags.wallet_role_enabled") public static final int config_defaultWallet; field public static final int config_devicePolicyManagement = 17039421; // 0x104003d field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020 @@ -1595,12 +1596,14 @@ package android.app.ambientcontext { method public int getDensityLevel(); method @NonNull public java.time.Instant getEndTime(); method public int getEventType(); + method @FlaggedApi("android.app.ambient_heart_rate") @IntRange(from=0xffffffff) public int getRatePerMinute(); method @NonNull public java.time.Instant getStartTime(); method @NonNull public android.os.PersistableBundle getVendorData(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR; field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3 field public static final int EVENT_COUGH = 1; // 0x1 + field @FlaggedApi("android.app.ambient_heart_rate") public static final int EVENT_HEART_RATE = 4; // 0x4 field public static final int EVENT_SNORE = 2; // 0x2 field public static final int EVENT_UNKNOWN = 0; // 0x0 field public static final int EVENT_VENDOR_WEARABLE_START = 100000; // 0x186a0 @@ -1620,6 +1623,7 @@ package android.app.ambientcontext { method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setDensityLevel(int); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEndTime(@NonNull java.time.Instant); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEventType(int); + method @FlaggedApi("android.app.ambient_heart_rate") @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setRatePerMinute(@IntRange(from=0xffffffff) int); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setStartTime(@NonNull java.time.Instant); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setVendorData(@NonNull android.os.PersistableBundle); } @@ -9875,49 +9879,6 @@ package android.net.wifi.sharedconnectivity.service { } -package android.nfc { - - public final class NfcAdapter { - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); - method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); - method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableWlc(boolean); - method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState(); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int); - method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn(); - method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported(); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported(); - method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener); - method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler); - method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean); - method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean); - method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener); - method @FlaggedApi("android.nfc.enable_nfc_charging") public void unregisterWlcStateListener(@NonNull android.nfc.NfcAdapter.WlcStateListener); - field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; - field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff - field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0 - field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe - } - - public static interface NfcAdapter.ControllerAlwaysOnListener { - method public void onControllerAlwaysOnChanged(boolean); - } - - public static interface NfcAdapter.NfcUnlockHandler { - method public boolean onUnlockAttempted(android.nfc.Tag); - } - - @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener { - method public void onWlcStateChanged(@NonNull android.nfc.WlcLDeviceInfo); - } - -} - package android.nfc.cardemulation { @FlaggedApi("android.nfc.enable_nfc_mainline") public final class AidGroup implements android.os.Parcelable { @@ -9966,10 +9927,6 @@ package android.nfc.cardemulation { field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR; } - public final class CardEmulation { - method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int); - } - @FlaggedApi("android.nfc.enable_nfc_mainline") public final class NfcFServiceInfo implements android.os.Parcelable { ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents(); @@ -14679,6 +14636,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMobileDataPolicyEnabled(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isNrDualConnectivityEnabled(); + method @FlaggedApi("com.android.internal.telephony.flags.enable_modem_cipher_transparency") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isNullCipherNotificationsEnabled(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String); @@ -14718,6 +14676,7 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean); method @FlaggedApi("com.android.internal.telephony.flags.enable_identifier_disclosure_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableCellularIdentifierDisclosureNotifications(boolean); + method @FlaggedApi("com.android.internal.telephony.flags.enable_modem_cipher_transparency") @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setEnableNullCipherNotifications(boolean); 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); @@ -15125,7 +15084,7 @@ package android.telephony.data { method public final void notifyDataCallListChanged(java.util.List<android.telephony.data.DataCallResponse>); method public final void notifyDataProfileUnthrottled(@NonNull android.telephony.data.DataProfile); method public void requestDataCallList(@NonNull android.telephony.data.DataServiceCallback); - method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public void requestValidation(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @FlaggedApi("com.android.internal.telephony.flags.network_validation") public void requestNetworkValidation(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback); @@ -16332,7 +16291,7 @@ package android.telephony.ims { public interface RegistrationManager { field public static final int SUGGESTED_ACTION_NONE = 0; // 0x0 - field @FlaggedApi("com.android.internal.telephony.flags.add_rat_related_suggested_action_to_ims_registration") public static final int SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK = 4; // 0x4 + field @FlaggedApi("com.android.internal.telephony.flags.add_rat_related_suggested_action_to_ims_registration") public static final int SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS = 4; // 0x4 field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK = 1; // 0x1 field public static final int SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.add_rat_related_suggested_action_to_ims_registration") public static final int SUGGESTED_ACTION_TRIGGER_RAT_BLOCK = 3; // 0x3 @@ -17030,8 +16989,8 @@ package android.telephony.satellite { @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class PointingInfo implements android.os.Parcelable { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int describeContents(); - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getSatelliteAzimuthDegrees(); - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public float getSatelliteElevationDegrees(); + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @FloatRange(from=0xffffff4c, to=180) public float getSatelliteAzimuthDegrees(); + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @FloatRange(from=0xffffffa6, to=90) public float getSatelliteElevationDegrees(); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void writeToParcel(@NonNull android.os.Parcel, int); field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @NonNull public static final android.os.Parcelable.Creator<android.telephony.satellite.PointingInfo> CREATOR; } @@ -17064,13 +17023,14 @@ package android.telephony.satellite { @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteManager { method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getAllSatellitePlmnsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback) throws android.telephony.satellite.SatelliteManager.SatelliteException; method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback); - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteStateCallback); + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); @@ -17091,7 +17051,7 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteCapabilitiesChanged(@NonNull android.telephony.satellite.SatelliteCapabilitiesCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback); - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteStateCallback); + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback); field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2 field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1 @@ -17161,12 +17121,12 @@ package android.telephony.satellite { method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public int getErrorCode(); } - @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteProvisionStateCallback { - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteProvisionStateChanged(boolean); + @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteModemStateCallback { + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteModemStateChanged(int); } - @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteStateCallback { - method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteModemStateChanged(int); + @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteProvisionStateCallback { + method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void onSatelliteProvisionStateChanged(boolean); } @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public interface SatelliteTransmissionUpdateCallback { diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index b2a28b2127bc..6c83fd04b76b 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -239,14 +239,6 @@ BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS: Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION: Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: - Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: - Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: - Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior -BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: - Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED: Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER: @@ -1077,86 +1069,6 @@ RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener): Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): - Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): - Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): - Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): - Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): - Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): - Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): - Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): - Method 'decrement' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): - Method 'increment' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): - Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#restore(int): - Method 'restore' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): - Method 'transfer' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): - Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): - Method 'readPages' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): - Method 'writePage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): - Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#isWritable(): - Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): - Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): - Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): - Method 'format' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): - Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#getTimeout(): - Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): - Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): - Method 'transceive' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#close(): - Method 'close' documentation mentions permissions without declaring @RequiresPermission -RequiresPermission: android.nfc.tech.TagTechnology#connect(): - Method 'connect' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.BugreportManager#cancelBugreport(): Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission RequiresPermission: android.os.BugreportManager#preDumpUiData(): @@ -1863,10 +1775,6 @@ SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsCh SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler): SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.addOnSession2TokensChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle): - SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions -SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler): - SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String): SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int): @@ -1933,8 +1841,6 @@ SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED: Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE: Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) -SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: - Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED: Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED: @@ -2359,8 +2265,8 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#provisionSatelliteSer New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.provisionSatelliteService(String,byte[],android.os.CancellationSignal,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>) UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteDatagram(java.util.concurrent.Executor, android.telephony.satellite.SatelliteDatagramCallback): New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteDatagram(java.util.concurrent.Executor,android.telephony.satellite.SatelliteDatagramCallback) -UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteModemStateChanged(java.util.concurrent.Executor, android.telephony.satellite.SatelliteStateCallback): - New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteModemStateChanged(java.util.concurrent.Executor,android.telephony.satellite.SatelliteStateCallback) +UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteModemStateChanged(java.util.concurrent.Executor, android.telephony.satellite.SatelliteModemStateCallback): + New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteModemStateChanged(java.util.concurrent.Executor,android.telephony.satellite.SatelliteModemStateCallback) UnflaggedApi: android.telephony.satellite.SatelliteManager#registerForSatelliteProvisionStateChanged(java.util.concurrent.Executor, android.telephony.satellite.SatelliteProvisionStateCallback): New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.registerForSatelliteProvisionStateChanged(java.util.concurrent.Executor,android.telephony.satellite.SatelliteProvisionStateCallback) UnflaggedApi: android.telephony.satellite.SatelliteManager#requestIsDemoModeEnabled(java.util.concurrent.Executor, android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>): @@ -2389,8 +2295,8 @@ UnflaggedApi: android.telephony.satellite.SatelliteManager#stopSatelliteTransmis New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.stopSatelliteTransmissionUpdates(android.telephony.satellite.SatelliteTransmissionUpdateCallback,java.util.concurrent.Executor,java.util.function.Consumer<java.lang.Integer>) UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteDatagram(android.telephony.satellite.SatelliteDatagramCallback): New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteDatagram(android.telephony.satellite.SatelliteDatagramCallback) -UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteStateCallback): - New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteStateCallback) +UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteModemStateCallback): + New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteModemStateChanged(android.telephony.satellite.SatelliteModemStateCallback) UnflaggedApi: android.telephony.satellite.SatelliteManager#unregisterForSatelliteProvisionStateChanged(android.telephony.satellite.SatelliteProvisionStateCallback): New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteManager.unregisterForSatelliteProvisionStateChanged(android.telephony.satellite.SatelliteProvisionStateCallback) UnflaggedApi: android.telephony.satellite.SatelliteManager.SatelliteException: @@ -2403,10 +2309,10 @@ UnflaggedApi: android.telephony.satellite.SatelliteProvisionStateCallback: New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteProvisionStateCallback UnflaggedApi: android.telephony.satellite.SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean): New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteProvisionStateCallback.onSatelliteProvisionStateChanged(boolean) -UnflaggedApi: android.telephony.satellite.SatelliteStateCallback: - New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteStateCallback -UnflaggedApi: android.telephony.satellite.SatelliteStateCallback#onSatelliteModemStateChanged(int): - New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteStateCallback.onSatelliteModemStateChanged(int) +UnflaggedApi: android.telephony.satellite.SatelliteModemStateCallback: + New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteModemStateCallback +UnflaggedApi: android.telephony.satellite.SatelliteModemStateCallback#onSatelliteModemStateChanged(int): + New API must be flagged with @FlaggedApi: method android.telephony.satellite.SatelliteModemStateCallback.onSatelliteModemStateChanged(int) UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback: New API must be flagged with @FlaggedApi: class android.telephony.satellite.SatelliteTransmissionUpdateCallback UnflaggedApi: android.telephony.satellite.SatelliteTransmissionUpdateCallback#onReceiveDatagramStateChanged(int, int, int): diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt index 51b8a11e1791..bbfa0ec3f3c2 100644 --- a/core/api/system-removed.txt +++ b/core/api/system-removed.txt @@ -142,17 +142,6 @@ package android.media.tv { } -package android.nfc { - - public final class NfcAdapter { - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush(); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush(); - method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int); - field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1 - } - -} - package android.os { public class Build { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 2e22071d72ad..bbe03a3d11a2 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3735,6 +3735,7 @@ package android.view.animation { public class AnimationUtils { method @FlaggedApi("android.view.flags.expected_presentation_time_read_only") public static void lockAnimationClock(long, long); + method public static void lockAnimationClock(long); method public static void unlockAnimationClock(); } diff --git a/core/java/Android.bp b/core/java/Android.bp index fb1e16a27d0b..eba500dd32b4 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -14,20 +14,12 @@ aidl_library { hdrs: ["android/hardware/HardwareBuffer.aidl"], } -// TODO (b/303286040): Remove this once |ENABLE_NFC_MAINLINE_FLAG| is rolled out -filegroup { - name: "framework-core-nfc-infcadapter-sources", - srcs: [ - "android/nfc/INfcAdapter.aidl", - ], - visibility: ["//frameworks/base/services/core"], -} - filegroup { name: "framework-core-sources", srcs: [ "**/*.java", "**/*.aidl", + ":framework-nfc-non-updatable-sources", ], visibility: ["//frameworks/base"], } diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java index 1e1f1554d3a2..5840f02a8650 100644 --- a/core/java/android/animation/ObjectAnimator.java +++ b/core/java/android/animation/ObjectAnimator.java @@ -25,8 +25,6 @@ import android.util.Log; import android.util.Property; import android.view.animation.AccelerateDecelerateInterpolator; -import java.lang.ref.WeakReference; - /** * This subclass of {@link ValueAnimator} provides support for animating properties on target objects. * The constructors of this class take parameters to define the target object that will be animated @@ -73,11 +71,7 @@ public final class ObjectAnimator extends ValueAnimator { private static final boolean DBG = false; - /** - * A weak reference to the target object on which the property exists, set - * in the constructor. We'll cancel the animation if this goes away. - */ - private WeakReference<Object> mTarget; + private Object mTarget; private String mPropertyName; @@ -919,7 +913,7 @@ public final class ObjectAnimator extends ValueAnimator { */ @Nullable public Object getTarget() { - return mTarget == null ? null : mTarget.get(); + return mTarget; } @Override @@ -929,7 +923,7 @@ public final class ObjectAnimator extends ValueAnimator { if (isStarted()) { cancel(); } - mTarget = target == null ? null : new WeakReference<Object>(target); + mTarget = target; // New target should cause re-initialization prior to starting mInitialized = false; } @@ -977,13 +971,6 @@ public final class ObjectAnimator extends ValueAnimator { @Override void animateValue(float fraction) { final Object target = getTarget(); - if (mTarget != null && target == null) { - // We lost the target reference, cancel and clean up. Note: we allow null target if the - /// target has never been set. - cancel(); - return; - } - super.animateValue(fraction); int numValues = mValues.length; for (int i = 0; i < numValues; ++i) { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index f9583d22cf58..2103055afe50 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1177,23 +1177,12 @@ public class Activity extends ContextThemeWrapper return mApplication; } - /** - * Whether this is a child {@link Activity} of an {@link ActivityGroup}. - * - * @deprecated {@link ActivityGroup} is deprecated. - */ - @Deprecated + /** Is this activity embedded inside of another activity? */ public final boolean isChild() { return mParent != null; } - /** - * Returns the parent {@link Activity} if this is a child {@link Activity} of an - * {@link ActivityGroup}. - * - * @deprecated {@link ActivityGroup} is deprecated. - */ - @Deprecated + /** Return the parent activity if this view is an embedded child. */ public final Activity getParent() { return mParent; } @@ -3075,7 +3064,7 @@ public class Activity extends ContextThemeWrapper } /** - * Request to put the freeform activity into fullscreen. The requester has to be the top-most + * Request to put the activity into fullscreen. The requester must be pinned or the top-most * activity of the focused display which can be verified using * {@link #onTopResumedActivityChanged(boolean)}. The request should also be a response to a * user input. When getting fullscreen and receiving corresponding diff --git a/core/java/android/app/ambient_context.aconfig b/core/java/android/app/ambient_context.aconfig new file mode 100644 index 000000000000..3f73da216b9f --- /dev/null +++ b/core/java/android/app/ambient_context.aconfig @@ -0,0 +1,8 @@ +package: "android.app" + +flag { + namespace: "biometrics_integration" + name: "ambient_heart_rate" + description: "Feature flag for adding heart rate api to ambient context." + bug: "318309481" +} diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java index b5c66ffa72a1..f94987e8495a 100644 --- a/core/java/android/app/ambientcontext/AmbientContextEvent.java +++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java @@ -16,7 +16,9 @@ package android.app.ambientcontext; +import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcelable; @@ -68,6 +70,14 @@ public final class AmbientContextEvent implements Parcelable { public static final int EVENT_BACK_DOUBLE_TAP = 3; /** + * The integer indicating a heart rate measurement was done. + * + * @see #getRatePerMinute + */ + @Event @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) + public static final int EVENT_HEART_RATE = 4; + + /** * Integer indicating the start of wearable vendor defined events that can be detected. * These depend on the vendor implementation. */ @@ -79,12 +89,16 @@ public final class AmbientContextEvent implements Parcelable { */ public static final String KEY_VENDOR_WEARABLE_EVENT_NAME = "wearable_event_name"; + /** Default value for the rate per minute data field. */ + private static final int RATE_PER_MINUTE_UNKNOWN = -1; + /** @hide */ @IntDef(prefix = { "EVENT_" }, value = { EVENT_UNKNOWN, EVENT_COUGH, EVENT_SNORE, EVENT_BACK_DOUBLE_TAP, + EVENT_HEART_RATE, EVENT_VENDOR_WEARABLE_START, }) @Retention(RetentionPolicy.SOURCE) @@ -170,6 +184,16 @@ public final class AmbientContextEvent implements Parcelable { return new PersistableBundle(); } + /** + * Rate per minute of the event during the start to end time. + * + * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown. + */ + private final @IntRange(from = -1) int mRatePerMinute; + private static int defaultRatePerMinute() { + return RATE_PER_MINUTE_UNKNOWN; + } + // Code below generated by codegen v1.0.23. @@ -179,6 +203,8 @@ public final class AmbientContextEvent implements Parcelable { // // To regenerate run: // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java + // then manually add @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) back to flagged + // APIs. // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -191,6 +217,7 @@ public final class AmbientContextEvent implements Parcelable { EVENT_COUGH, EVENT_SNORE, EVENT_BACK_DOUBLE_TAP, + EVENT_HEART_RATE, EVENT_VENDOR_WEARABLE_START }) @Retention(RetentionPolicy.SOURCE) @@ -209,6 +236,8 @@ public final class AmbientContextEvent implements Parcelable { return "EVENT_SNORE"; case EVENT_BACK_DOUBLE_TAP: return "EVENT_BACK_DOUBLE_TAP"; + case EVENT_HEART_RATE: + return "EVENT_HEART_RATE"; case EVENT_VENDOR_WEARABLE_START: return "EVENT_VENDOR_WEARABLE_START"; default: return Integer.toHexString(value); @@ -255,7 +284,8 @@ public final class AmbientContextEvent implements Parcelable { @NonNull Instant endTime, @LevelValue int confidenceLevel, @LevelValue int densityLevel, - @NonNull PersistableBundle vendorData) { + @NonNull PersistableBundle vendorData, + @IntRange(from = -1) int ratePerMinute) { this.mEventType = eventType; com.android.internal.util.AnnotationValidations.validate( EventCode.class, null, mEventType); @@ -274,6 +304,10 @@ public final class AmbientContextEvent implements Parcelable { this.mVendorData = vendorData; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mVendorData); + this.mRatePerMinute = ratePerMinute; + com.android.internal.util.AnnotationValidations.validate( + IntRange.class, null, mRatePerMinute, + "from", -1); // onConstructed(); // You can define this method to get a callback } @@ -330,6 +364,17 @@ public final class AmbientContextEvent implements Parcelable { return mVendorData; } + /** + * Rate per minute of the event during the start to end time. + * + * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown. + */ + @DataClass.Generated.Member + @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) + public @IntRange(from = -1) int getRatePerMinute() { + return mRatePerMinute; + } + @Override @DataClass.Generated.Member public String toString() { @@ -342,7 +387,8 @@ public final class AmbientContextEvent implements Parcelable { "endTime = " + mEndTime + ", " + "confidenceLevel = " + mConfidenceLevel + ", " + "densityLevel = " + mDensityLevel + ", " + - "vendorData = " + mVendorData + + "vendorData = " + mVendorData + ", " + + "ratePerMinute = " + mRatePerMinute + " }"; } @@ -380,6 +426,7 @@ public final class AmbientContextEvent implements Parcelable { dest.writeInt(mConfidenceLevel); dest.writeInt(mDensityLevel); dest.writeTypedObject(mVendorData, flags); + dest.writeInt(mRatePerMinute); } @Override @@ -399,6 +446,7 @@ public final class AmbientContextEvent implements Parcelable { int confidenceLevel = in.readInt(); int densityLevel = in.readInt(); PersistableBundle vendorData = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR); + int ratePerMinute = in.readInt(); this.mEventType = eventType; com.android.internal.util.AnnotationValidations.validate( @@ -418,6 +466,10 @@ public final class AmbientContextEvent implements Parcelable { this.mVendorData = vendorData; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mVendorData); + this.mRatePerMinute = ratePerMinute; + com.android.internal.util.AnnotationValidations.validate( + IntRange.class, null, mRatePerMinute, + "from", -1); // onConstructed(); // You can define this method to get a callback } @@ -449,6 +501,7 @@ public final class AmbientContextEvent implements Parcelable { private @LevelValue int mConfidenceLevel; private @LevelValue int mDensityLevel; private @NonNull PersistableBundle mVendorData; + private @IntRange(from = -1) int mRatePerMinute; private long mBuilderFieldsSet = 0L; @@ -525,10 +578,22 @@ public final class AmbientContextEvent implements Parcelable { return this; } + /** + * Rate per minute of the event during the start to end time. + */ + @DataClass.Generated.Member + @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) + public @NonNull Builder setRatePerMinute(@IntRange(from = -1) int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x40; + mRatePerMinute = value; + return this; + } + /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull AmbientContextEvent build() { checkNotUsed(); - mBuilderFieldsSet |= 0x40; // Mark builder used + mBuilderFieldsSet |= 0x80; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mEventType = defaultEventType(); @@ -548,18 +613,22 @@ public final class AmbientContextEvent implements Parcelable { if ((mBuilderFieldsSet & 0x20) == 0) { mVendorData = defaultVendorData(); } + if ((mBuilderFieldsSet & 0x40) == 0) { + mRatePerMinute = defaultRatePerMinute(); + } AmbientContextEvent o = new AmbientContextEvent( mEventType, mStartTime, mEndTime, mConfidenceLevel, mDensityLevel, - mVendorData); + mVendorData, + mRatePerMinute); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x40) != 0) { + if ((mBuilderFieldsSet & 0x80) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -567,10 +636,10 @@ public final class AmbientContextEvent implements Parcelable { } @DataClass.Generated( - time = 1671217108067L, + time = 1704895515931L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java", - inputSignatures = "public static final int EVENT_UNKNOWN\npublic static final int EVENT_COUGH\npublic static final int EVENT_SNORE\npublic static final int EVENT_BACK_DOUBLE_TAP\npublic static final int EVENT_VENDOR_WEARABLE_START\npublic static final java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final int LEVEL_UNKNOWN\npublic static final int LEVEL_LOW\npublic static final int LEVEL_MEDIUM_LOW\npublic static final int LEVEL_MEDIUM\npublic static final int LEVEL_MEDIUM_HIGH\npublic static final int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate static int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static int defaultConfidenceLevel()\nprivate static int defaultDensityLevel()\nprivate static android.os.PersistableBundle defaultVendorData()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + inputSignatures = "public static final int EVENT_UNKNOWN\npublic static final int EVENT_COUGH\npublic static final int EVENT_SNORE\npublic static final int EVENT_BACK_DOUBLE_TAP\npublic static final @android.app.ambientcontext.AmbientContextEvent.Event @android.annotation.FlaggedApi int EVENT_HEART_RATE\npublic static final int EVENT_VENDOR_WEARABLE_START\npublic static final java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\nprivate static final int RATE_PER_MINUTE_UNKNOWN\npublic static final int LEVEL_UNKNOWN\npublic static final int LEVEL_LOW\npublic static final int LEVEL_MEDIUM_LOW\npublic static final int LEVEL_MEDIUM\npublic static final int LEVEL_MEDIUM_HIGH\npublic static final int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate final @android.annotation.IntRange int mRatePerMinute\nprivate static int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static int defaultConfidenceLevel()\nprivate static int defaultDensityLevel()\nprivate static android.os.PersistableBundle defaultVendorData()\nprivate static int defaultRatePerMinute()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java index 637187120922..a41cb1fa6ea8 100644 --- a/core/java/android/app/backup/FullBackup.java +++ b/core/java/android/app/backup/FullBackup.java @@ -239,7 +239,7 @@ public class FullBackup { Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e); } - byte[] buffer = new byte[32 * 1024]; + byte[] buffer = new byte[64 * 1024]; final long origSize = size; FileInputStream in = new FileInputStream(data.getFileDescriptor()); while (size > 0) { diff --git a/core/java/android/app/wearable/OWNERS b/core/java/android/app/wearable/OWNERS index 073e2d79850b..497eaf0e40f1 100644 --- a/core/java/android/app/wearable/OWNERS +++ b/core/java/android/app/wearable/OWNERS @@ -1,3 +1,5 @@ charliewang@google.com +hackz@google.com oni@google.com +tomchan@google.com volnov@google.com
\ No newline at end of file diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 4cf9fcab9092..6204edc5b2e8 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -19,6 +19,7 @@ package android.appwidget; import static android.appwidget.flags.Flags.remoteAdapterConversion; import android.annotation.BroadcastBehavior; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; @@ -30,6 +31,7 @@ import android.annotation.UiThread; import android.annotation.UserIdInt; import android.app.IServiceConnection; import android.app.PendingIntent; +import android.appwidget.flags.Flags; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -1415,6 +1417,89 @@ public class AppWidgetManager { } } + /** + * Set a preview for this widget. This preview will be used instead of the provider's {@link + * AppWidgetProviderInfo#previewLayout previewLayout} or {@link + * AppWidgetProviderInfo#previewImage previewImage} for previewing the widget in the widget + * picker and pin app widget flow. + * + * @param provider The {@link ComponentName} for the {@link android.content.BroadcastReceiver + * BroadcastReceiver} provider for the AppWidget you intend to provide a preview for. + * @param widgetCategories The categories that this preview should be used for. This can be a + * single category or combination of categories. If multiple categories are specified, + * then this preview will be used for each of those categories. For example, if you + * set a preview for WIDGET_CATEGORY_HOME_SCREEN | WIDGET_CATEGORY_KEYGUARD, the preview will + * be used when picking widgets for the home screen and keyguard. + * + * <p>Note: You should only use the widget categories that the provider supports, as defined + * in {@link AppWidgetProviderInfo#widgetCategory}. + * @param preview This preview will be used for previewing the provider when picking widgets for + * the selected categories. + * + * @see AppWidgetProviderInfo#WIDGET_CATEGORY_HOME_SCREEN + * @see AppWidgetProviderInfo#WIDGET_CATEGORY_KEYGUARD + * @see AppWidgetProviderInfo#WIDGET_CATEGORY_SEARCHBOX + */ + @FlaggedApi(Flags.FLAG_GENERATED_PREVIEWS) + public void setWidgetPreview(@NonNull ComponentName provider, + @AppWidgetProviderInfo.CategoryFlags int widgetCategories, + @NonNull RemoteViews preview) { + try { + mService.setWidgetPreview(provider, widgetCategories, preview); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the RemoteViews previews for this widget. + * + * @param provider The {@link ComponentName} for the {@link android.content.BroadcastReceiver + * BroadcastReceiver} provider for the AppWidget you intend to get a preview for. + * @param profile The profile in which the provider resides. Passing null is equivalent + * to querying for only the calling user. + * @param widgetCategory The widget category for which you want to display previews. This should + * be a single category. If a combination of categories is provided, this function will + * return a preview that matches at least one of the categories. + * + * @return The widget preview for the selected category, if available. + * @see AppWidgetProviderInfo#generatedPreviewCategories + */ + @Nullable + @FlaggedApi(Flags.FLAG_GENERATED_PREVIEWS) + public RemoteViews getWidgetPreview(@NonNull ComponentName provider, + @Nullable UserHandle profile, @AppWidgetProviderInfo.CategoryFlags int widgetCategory) { + try { + if (profile == null) { + profile = mContext.getUser(); + } + return mService.getWidgetPreview(mPackageName, provider, profile.getIdentifier(), + widgetCategory); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove this provider's preview for the specified widget categories. If the provider does not + * have a preview for the specified widget category, this is a no-op. + * + * @param provider The AppWidgetProvider to remove previews for. + * @param widgetCategories The categories of the preview to remove. For example, removing the + * preview for WIDGET_CATEGORY_HOME_SCREEN | WIDGET_CATEGORY_KEYGUARD will remove the + * previews for both categories. + */ + @FlaggedApi(Flags.FLAG_GENERATED_PREVIEWS) + public void removeWidgetPreview(@NonNull ComponentName provider, + @AppWidgetProviderInfo.CategoryFlags int widgetCategories) { + try { + mService.removeWidgetPreview(provider, widgetCategories); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @UiThread private static @NonNull Executor createUpdateExecutorIfNull() { if (sUpdateExecutor == null) { diff --git a/core/java/android/appwidget/AppWidgetProviderInfo.java b/core/java/android/appwidget/AppWidgetProviderInfo.java index e56e53a4a38b..1a80cac2f06a 100644 --- a/core/java/android/appwidget/AppWidgetProviderInfo.java +++ b/core/java/android/appwidget/AppWidgetProviderInfo.java @@ -16,6 +16,10 @@ package android.appwidget; +import static android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS; +import static android.appwidget.flags.Flags.generatedPreviews; + +import android.annotation.FlaggedApi; import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; @@ -358,6 +362,20 @@ public class AppWidgetProviderInfo implements Parcelable { /** @hide */ public boolean isExtendedFromAppWidgetProvider; + /** + * Flags indicating the widget categories for which generated previews are available. + * These correspond to the previews set by this provider with + * {@link AppWidgetManager#setWidgetPreview}. + * + * @see #WIDGET_CATEGORY_HOME_SCREEN + * @see #WIDGET_CATEGORY_KEYGUARD + * @see #WIDGET_CATEGORY_SEARCHBOX + * @see AppWidgetManager#getWidgetPreview + */ + @FlaggedApi(FLAG_GENERATED_PREVIEWS) + @SuppressLint("MutableBareField") + public int generatedPreviewCategories; + public AppWidgetProviderInfo() { } @@ -391,6 +409,9 @@ public class AppWidgetProviderInfo implements Parcelable { this.widgetFeatures = in.readInt(); this.descriptionRes = in.readInt(); this.isExtendedFromAppWidgetProvider = in.readBoolean(); + if (generatedPreviews()) { + generatedPreviewCategories = in.readInt(); + } } /** @@ -515,6 +536,9 @@ public class AppWidgetProviderInfo implements Parcelable { out.writeInt(this.widgetFeatures); out.writeInt(this.descriptionRes); out.writeBoolean(this.isExtendedFromAppWidgetProvider); + if (generatedPreviews()) { + out.writeInt(this.generatedPreviewCategories); + } } @Override @@ -545,6 +569,9 @@ public class AppWidgetProviderInfo implements Parcelable { that.widgetFeatures = this.widgetFeatures; that.descriptionRes = this.descriptionRes; that.isExtendedFromAppWidgetProvider = this.isExtendedFromAppWidgetProvider; + if (generatedPreviews()) { + that.generatedPreviewCategories = this.generatedPreviewCategories; + } return that; } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index c7a75ed5ea9c..e9b94c9f5791 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -41,6 +41,7 @@ import android.content.res.Configuration; import android.database.Cursor; import android.database.MatrixCursor; import android.database.SQLException; +import android.multiuser.Flags; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; @@ -146,6 +147,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall private boolean mExported; private boolean mNoPerms; private boolean mSingleUser; + private boolean mSystemUserOnly; private SparseBooleanArray mUsersRedirectedToOwnerForMedia = new SparseBooleanArray(); private ThreadLocal<AttributionSource> mCallingAttributionSource; @@ -377,7 +379,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall != PermissionChecker.PERMISSION_GRANTED && getContext().checkUriPermission(userUri, Binder.getCallingPid(), callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION) - != PackageManager.PERMISSION_GRANTED) { + != PackageManager.PERMISSION_GRANTED + && !deniedAccessSystemUserOnlyProvider(callingUserId, + mSystemUserOnly)) { FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION, enumCheckUriPermission, callingUid, uri.getAuthority(), type); @@ -865,6 +869,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall boolean checkUser(int pid, int uid, Context context) { final int callingUserId = UserHandle.getUserId(uid); + if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) { + return false; + } + if (callingUserId == context.getUserId() || mSingleUser) { return true; } @@ -987,6 +995,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall // last chance, check against any uri grants final int callingUserId = UserHandle.getUserId(uid); + if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) { + return PermissionChecker.PERMISSION_HARD_DENIED; + } final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid)) ? maybeAddUserId(uri, callingUserId) : uri; if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION) @@ -2623,6 +2634,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall setPathPermissions(info.pathPermissions); mExported = info.exported; mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0; + mSystemUserOnly = (info.flags & ProviderInfo.FLAG_SYSTEM_USER_ONLY) != 0; setAuthorities(info.authority); } if (Build.IS_DEBUGGABLE) { @@ -2756,6 +2768,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall String auth = uri.getAuthority(); if (!mSingleUser) { int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT); + if (deniedAccessSystemUserOnlyProvider(mContext.getUserId(), + mSystemUserOnly)) { + throw new SecurityException("Trying to query a SYSTEM user only content" + + " provider from user:" + mContext.getUserId()); + } if (userId != UserHandle.USER_CURRENT && userId != mContext.getUserId() // Since userId specified in content uri, the provider userId would be @@ -2929,4 +2946,16 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall Trace.traceBegin(traceTag, methodName + subInfo); } } + /** + * Return true if access to content provider is denied because it's a SYSTEM user only + * provider and the calling user is not the SYSTEM user. + * + * @param callingUserId UserId of the caller accessing the content provider. + * @param systemUserOnly true when the content provider is only available for the SYSTEM user. + */ + private static boolean deniedAccessSystemUserOnlyProvider(int callingUserId, + boolean systemUserOnly) { + return Flags.enableSystemUserOnlyForServicesAndProviders() + && (callingUserId != UserHandle.USER_SYSTEM && systemUserOnly); + } } diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS index 90c3d04d62d0..a37408b7d847 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -4,6 +4,7 @@ per-file ContextWrapper.java = * per-file *Content* = file:/services/core/java/com/android/server/am/OWNERS per-file *Sync* = file:/services/core/java/com/android/server/am/OWNERS per-file IntentFilter.java = file:/PACKAGE_MANAGER_OWNERS +per-file UriRelativeFilter* = file:/PACKAGE_MANAGER_OWNERS per-file IntentFilter.java = file:/services/core/java/com/android/server/am/OWNERS per-file Intent.java = file:/INTENT_OWNERS per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java index 9e553dbfb719..de33fa8b2328 100644 --- a/core/java/android/content/pm/ProviderInfo.java +++ b/core/java/android/content/pm/ProviderInfo.java @@ -89,6 +89,15 @@ public final class ProviderInfo extends ComponentInfo public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000; /** + * Bit in {@link #flags}: If set, this provider will only be available + * for the system user. + * Set from the android.R.attr#systemUserOnly attribute. + * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY} + * @hide + */ + public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY; + + /** * Bit in {@link #flags}: If set, a single instance of the provider will * run for all users on the device. Set from the * {@link android.R.attr#singleUser} attribute. diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index ae46c027505e..2b378b1f09d0 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -101,6 +101,14 @@ public class ServiceInfo extends ComponentInfo public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000; /** + * @hide Bit in {@link #flags}: If set, this service will only be available + * for the system user. + * Set from the android.R.attr#systemUserOnly attribute. + * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY} + */ + public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY; + + /** * Bit in {@link #flags}: If set, a single instance of the service will * run for all users on the device. Set from the * {@link android.R.attr#singleUser} attribute. diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index c7797c719e2c..10368653f0c4 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -70,4 +70,11 @@ flag { namespace: "profile_experiences" description: "Add support for Private Space in resolver sheet" bug: "307515485" -}
\ No newline at end of file +} +flag { + name: "enable_system_user_only_for_services_and_providers" + namespace: "multiuser" + description: "Enable systemUserOnly manifest attribute for services and providers." + bug: "302354856" + is_fixed_read_only: true +} diff --git a/core/java/android/credentials/GetCandidateCredentialsException.java b/core/java/android/credentials/GetCandidateCredentialsException.java index 40650d02a93e..0ac5f6c01212 100644 --- a/core/java/android/credentials/GetCandidateCredentialsException.java +++ b/core/java/android/credentials/GetCandidateCredentialsException.java @@ -46,6 +46,17 @@ public class GetCandidateCredentialsException extends Exception { "android.credentials.GetCandidateCredentialsException.TYPE_NO_CREDENTIAL"; @NonNull + public static final String TYPE_USER_CANCELED = + "android.credentials.GetCredentialException.TYPE_USER_CANCELED"; + /** + * The error type value for when the given operation failed due to internal interruption. + * Retrying the same operation should fix the error. + */ + @NonNull + public static final String TYPE_INTERRUPTED = + "android.credentials.GetCredentialException.TYPE_INTERRUPTED"; + + @NonNull private final String mType; /** Returns the specific exception type. */ diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 8c1ea5f445cf..a0f4d8df0bd5 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricManager.Authenticators; import static android.hardware.biometrics.Flags.FLAG_ADD_KEY_AGREEMENT_CRYPTO_OBJECT; import static android.hardware.biometrics.Flags.FLAG_GET_OP_ID_CRYPTO_OBJECT; +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; @@ -208,6 +209,12 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan /** * Optional: Sets a description that will be shown on the prompt. + * + * <p> Note that the description set by {@link Builder#setDescription(CharSequence)} will be + * overridden by {@link Builder#setContentView(PromptContentView)}. The view provided to + * {@link Builder#setContentView(PromptContentView)} will be used if both methods are + * called. + * * @param description The description to display. * @return This builder. */ @@ -218,6 +225,24 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } /** + * Optional: Sets application customized content view that will be shown on the prompt. + * + * <p> Note that the description set by {@link Builder#setDescription(CharSequence)} will be + * overridden by {@link Builder#setContentView(PromptContentView)}. The view provided to + * {@link Builder#setContentView(PromptContentView)} will be used if both methods are + * called. + * + * @param view The customized view information. + * @return This builder.re + */ + @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) + @NonNull + public BiometricPrompt.Builder setContentView(@NonNull PromptContentView view) { + mPromptInfo.setContentView(view); + return this; + } + + /** * @param service * @return This builder. * @hide @@ -698,6 +723,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan } /** + * Gets the content view for the prompt, as set by + * {@link Builder#setContentView(PromptContentView)}. + * + * @return The content view for the prompt, or null if the prompt has no content view. + */ + @FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) + @Nullable + public PromptContentView getContentView() { + return mPromptInfo.getContentView(); + } + + /** * Gets the negative button text for the prompt, as set by * {@link Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}. * @return The negative button text for the prompt, or null if no negative button text was set. diff --git a/core/java/android/hardware/biometrics/PromptContentListItem.java b/core/java/android/hardware/biometrics/PromptContentListItem.java new file mode 100644 index 000000000000..fa3783d6d874 --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentListItem.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; + +/** + * A list item shown on {@link PromptVerticalListContentView}. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +public interface PromptContentListItem { +} + diff --git a/core/java/android/hardware/biometrics/PromptContentListItemBulletedText.java b/core/java/android/hardware/biometrics/PromptContentListItemBulletedText.java new file mode 100644 index 000000000000..c31f8a63bcb8 --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentListItemBulletedText.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A list item with bulleted text shown on {@link PromptVerticalListContentView}. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +public final class PromptContentListItemBulletedText implements PromptContentListItemParcelable { + private final CharSequence mText; + + /** + * A list item with bulleted text shown on {@link PromptVerticalListContentView}. + * + * @param text The text of this list item. + */ + public PromptContentListItemBulletedText(@NonNull CharSequence text) { + mText = text; + } + + /** + * @hide + */ + @NonNull + public CharSequence getText() { + return mText; + } + + /** + * {@inheritDoc} + */ + @Override + public int describeContents() { + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeCharSequence(mText); + } + + /** + * @see Parcelable.Creator + */ + @NonNull + public static final Creator<PromptContentListItemBulletedText> CREATOR = new Creator<>() { + @Override + public PromptContentListItemBulletedText createFromParcel(Parcel in) { + return new PromptContentListItemBulletedText(in.readCharSequence()); + } + + @Override + public PromptContentListItemBulletedText[] newArray(int size) { + return new PromptContentListItemBulletedText[size]; + } + }; +} diff --git a/core/java/android/hardware/biometrics/PromptContentListItemParcelable.java b/core/java/android/hardware/biometrics/PromptContentListItemParcelable.java new file mode 100644 index 000000000000..15271f003c50 --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentListItemParcelable.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; +import android.os.Parcelable; + +/** + * A parcelable {@link PromptContentListItem}. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +sealed interface PromptContentListItemParcelable extends PromptContentListItem, Parcelable + permits PromptContentListItemPlainText, PromptContentListItemBulletedText { +} diff --git a/core/java/android/hardware/biometrics/PromptContentListItemPlainText.java b/core/java/android/hardware/biometrics/PromptContentListItemPlainText.java new file mode 100644 index 000000000000..d72a7586d6ad --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentListItemPlainText.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A list item with plain text shown on {@link PromptVerticalListContentView}. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +public final class PromptContentListItemPlainText implements PromptContentListItemParcelable { + private final CharSequence mText; + + /** + * A list item with plain text shown on {@link PromptVerticalListContentView}. + * + * @param text The text of this list item. + */ + public PromptContentListItemPlainText(@NonNull CharSequence text) { + mText = text; + } + + /** + * @hide + */ + @NonNull + public CharSequence getText() { + return mText; + } + + /** + * {@inheritDoc} + */ + @Override + public int describeContents() { + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeCharSequence(mText); + } + + /** + * @see Parcelable.Creator + */ + @NonNull + public static final Creator<PromptContentListItemPlainText> CREATOR = new Creator<>() { + @Override + public PromptContentListItemPlainText createFromParcel(Parcel in) { + return new PromptContentListItemPlainText(in.readCharSequence()); + } + + @Override + public PromptContentListItemPlainText[] newArray(int size) { + return new PromptContentListItemPlainText[size]; + } + }; +} diff --git a/core/java/android/hardware/biometrics/PromptContentView.java b/core/java/android/hardware/biometrics/PromptContentView.java new file mode 100644 index 000000000000..ff9313e8d3f0 --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentView.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; + +/** + * Contains the information of the template of content view for Biometric Prompt. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +public interface PromptContentView { +} diff --git a/core/java/android/hardware/biometrics/PromptContentViewParcelable.java b/core/java/android/hardware/biometrics/PromptContentViewParcelable.java new file mode 100644 index 000000000000..43b965bb696d --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptContentViewParcelable.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; +import android.os.Parcelable; + +/** + * A parcelable {@link PromptContentView}. + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +sealed interface PromptContentViewParcelable extends PromptContentView, Parcelable + permits PromptVerticalListContentView { +} diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java index 24cfd1641410..c73ebd4dbe76 100644 --- a/core/java/android/hardware/biometrics/PromptInfo.java +++ b/core/java/android/hardware/biometrics/PromptInfo.java @@ -35,6 +35,7 @@ public class PromptInfo implements Parcelable { @Nullable private CharSequence mSubtitle; private boolean mUseDefaultSubtitle; @Nullable private CharSequence mDescription; + @Nullable private PromptContentViewParcelable mContentView; @Nullable private CharSequence mDeviceCredentialTitle; @Nullable private CharSequence mDeviceCredentialSubtitle; @Nullable private CharSequence mDeviceCredentialDescription; @@ -60,6 +61,8 @@ public class PromptInfo implements Parcelable { mSubtitle = in.readCharSequence(); mUseDefaultSubtitle = in.readBoolean(); mDescription = in.readCharSequence(); + mContentView = in.readParcelable(PromptContentViewParcelable.class.getClassLoader(), + PromptContentViewParcelable.class); mDeviceCredentialTitle = in.readCharSequence(); mDeviceCredentialSubtitle = in.readCharSequence(); mDeviceCredentialDescription = in.readCharSequence(); @@ -100,6 +103,7 @@ public class PromptInfo implements Parcelable { dest.writeCharSequence(mSubtitle); dest.writeBoolean(mUseDefaultSubtitle); dest.writeCharSequence(mDescription); + dest.writeParcelable(mContentView, 0); dest.writeCharSequence(mDeviceCredentialTitle); dest.writeCharSequence(mDeviceCredentialSubtitle); dest.writeCharSequence(mDeviceCredentialDescription); @@ -176,6 +180,10 @@ public class PromptInfo implements Parcelable { mDescription = description; } + public void setContentView(PromptContentView view) { + mContentView = (PromptContentViewParcelable) view; + } + public void setDeviceCredentialTitle(CharSequence deviceCredentialTitle) { mDeviceCredentialTitle = deviceCredentialTitle; } @@ -257,6 +265,15 @@ public class PromptInfo implements Parcelable { return mDescription; } + /** + * Gets the content view for the prompt. + * + * @return The content view for the prompt, or null if the prompt has no content view. + */ + public PromptContentView getContentView() { + return mContentView; + } + public CharSequence getDeviceCredentialTitle() { return mDeviceCredentialTitle; } diff --git a/core/java/android/hardware/biometrics/PromptVerticalListContentView.java b/core/java/android/hardware/biometrics/PromptVerticalListContentView.java new file mode 100644 index 000000000000..f3cb189a5df5 --- /dev/null +++ b/core/java/android/hardware/biometrics/PromptVerticalListContentView.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2023 The Android Open 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.biometrics; + +import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Contains the information of the template of vertical list content view for Biometric Prompt. Note + * that there are limits on the item count and the number of characters allowed for each item's + * text. + * <p> + * Here's how you'd set a <code>PromptVerticalListContentView</code> on a Biometric Prompt: + * <pre class="prettyprint"> + * BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(...) + * .setTitle(...) + * .setSubTitle(...) + * .setContentView(new PromptVerticalListContentView.Builder() + * .setDescription("test description") + * .addListItem(new PromptContentListItemPlainText("test item 1")) + * .addListItem(new PromptContentListItemPlainText("test item 2")) + * .addListItem(new PromptContentListItemBulletedText("test item 3")) + * .build()) + * .build(); + * </pre> + */ +@FlaggedApi(FLAG_CUSTOM_BIOMETRIC_PROMPT) +public final class PromptVerticalListContentView implements PromptContentViewParcelable { + private static final int MAX_ITEM_NUMBER = 20; + private static final int MAX_EACH_ITEM_CHARACTER_NUMBER = 640; + private final List<PromptContentListItemParcelable> mContentList; + private final CharSequence mDescription; + + private PromptVerticalListContentView( + @NonNull List<PromptContentListItemParcelable> contentList, + @NonNull CharSequence description) { + mContentList = contentList; + mDescription = description; + } + + private PromptVerticalListContentView(Parcel in) { + mContentList = in.readArrayList( + PromptContentListItemParcelable.class.getClassLoader(), + PromptContentListItemParcelable.class); + mDescription = in.readCharSequence(); + } + + /** + * Returns the maximum count of the list items. + */ + public static int getMaxItemCount() { + return MAX_ITEM_NUMBER; + } + + /** + * Returns the maximum number of characters allowed for each item's text. + */ + public static int getMaxEachItemCharacterNumber() { + return MAX_EACH_ITEM_CHARACTER_NUMBER; + } + + /** + * Gets the description for the content view, as set by + * {@link PromptVerticalListContentView.Builder#setDescription(CharSequence)}. + * + * @return The description for the content view, or null if the content view has no description. + */ + @Nullable + public CharSequence getDescription() { + return mDescription; + } + + /** + * Gets the list of ListItem on the content view, as set by + * {@link PromptVerticalListContentView.Builder#addListItem(PromptContentListItem)}. + * + * @return The item list on the content view. + */ + @NonNull + public List<PromptContentListItem> getListItems() { + return new ArrayList<>(mContentList); + } + + /** + * {@inheritDoc} + */ + @Override + public int describeContents() { + return 0; + } + + /** + * {@inheritDoc} + */ + @Override + public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) { + dest.writeList(mContentList); + dest.writeCharSequence(mDescription); + } + + /** + * @see Parcelable.Creator + */ + @NonNull + public static final Creator<PromptVerticalListContentView> CREATOR = new Creator<>() { + @Override + public PromptVerticalListContentView createFromParcel(Parcel in) { + return new PromptVerticalListContentView(in); + } + + @Override + public PromptVerticalListContentView[] newArray(int size) { + return new PromptVerticalListContentView[size]; + } + }; + + + /** + * A builder that collects arguments to be shown on the vertical list view. + */ + public static final class Builder { + private final List<PromptContentListItemParcelable> mContentList = new ArrayList<>(); + private CharSequence mDescription; + + /** + * Optional: Sets a description that will be shown on the content view. + * + * @param description The description to display. + * @return This builder. + */ + @NonNull + public Builder setDescription(@NonNull CharSequence description) { + mDescription = description; + return this; + } + + /** + * Optional: Adds a list item in the current row. Maximum {@value MAX_ITEM_NUMBER} items in + * total. + * + * @param listItem The list item view to display + * @return This builder. + */ + @NonNull + public Builder addListItem(@NonNull PromptContentListItem listItem) { + if (doesListItemExceedsCharLimit(listItem)) { + throw new IllegalStateException( + "The character number of list item exceeds " + + MAX_EACH_ITEM_CHARACTER_NUMBER); + } + mContentList.add((PromptContentListItemParcelable) listItem); + return this; + } + + private boolean doesListItemExceedsCharLimit(PromptContentListItem listItem) { + if (listItem instanceof PromptContentListItemPlainText) { + return ((PromptContentListItemPlainText) listItem).getText().length() + > MAX_EACH_ITEM_CHARACTER_NUMBER; + } else if (listItem instanceof PromptContentListItemBulletedText) { + return ((PromptContentListItemBulletedText) listItem).getText().length() + > MAX_EACH_ITEM_CHARACTER_NUMBER; + } else { + return false; + } + } + + + /** + * Creates a {@link PromptVerticalListContentView}. + * + * @return An instance of {@link PromptVerticalListContentView}. + */ + @NonNull + public PromptVerticalListContentView build() { + if (mContentList.size() > MAX_ITEM_NUMBER) { + throw new IllegalStateException( + "The number of list items exceeds " + MAX_ITEM_NUMBER); + } + return new PromptVerticalListContentView(mContentList, mDescription); + } + } +} diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig index 375fdb5ec65a..3ba8be4cc2ab 100644 --- a/core/java/android/hardware/biometrics/flags.aconfig +++ b/core/java/android/hardware/biometrics/flags.aconfig @@ -21,3 +21,10 @@ flag { bug: "307601768" } +flag { + name: "custom_biometric_prompt" + namespace: "biometrics_framework" + description: "Feature flag for adding a custom content view API to BiometricPrompt.Builder." + bug: "302735104" +} + diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 3affb73d1075..0cd1c8ca89fe 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -79,6 +79,8 @@ import android.util.Log; import android.util.Range; import android.util.Size; +import com.android.internal.camera.flags.Flags; + import dalvik.annotation.optimization.FastNative; import dalvik.system.VMRuntime; @@ -1795,49 +1797,57 @@ public class CameraMetadataNative implements Parcelable { return false; } - long[] tsArray = new long[samples.length]; - float[] intrinsicsArray = new float[samples.length * 5]; - for (int i = 0; i < samples.length; i++) { - tsArray[i] = samples[i].getTimestamp(); - System.arraycopy(samples[i].getLensIntrinsics(), 0, intrinsicsArray, 5*i, 5); + if (Flags.concertMode()) { + long[] tsArray = new long[samples.length]; + float[] intrinsicsArray = new float[samples.length * 5]; + for (int i = 0; i < samples.length; i++) { + tsArray[i] = samples[i].getTimestampNanos(); + System.arraycopy(samples[i].getLensIntrinsics(), 0, intrinsicsArray, 5 * i, 5); - } - setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray); - setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray); + } + setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray); + setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray); - return true; + return true; + } else { + return false; + } } private LensIntrinsicsSample[] getLensIntrinsicSamples() { - long[] timestamps = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS); - float[] intrinsics = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES); + if (Flags.concertMode()) { + long[] timestamps = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS); + float[] intrinsics = getBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES); - if (timestamps == null) { - if (intrinsics != null) { - throw new AssertionError("timestamps is null but intrinsics is not"); - } + if (timestamps == null) { + if (intrinsics != null) { + throw new AssertionError("timestamps is null but intrinsics is not"); + } - return null; - } + return null; + } - if (intrinsics == null) { - throw new AssertionError("timestamps is not null but intrinsics is"); - } else if((intrinsics.length % 5) != 0) { - throw new AssertionError("intrinsics are not multiple of 5"); - } + if (intrinsics == null) { + throw new AssertionError("timestamps is not null but intrinsics is"); + } else if ((intrinsics.length % 5) != 0) { + throw new AssertionError("intrinsics are not multiple of 5"); + } - if ((intrinsics.length / 5) != timestamps.length) { - throw new AssertionError(String.format( - "timestamps has %d entries but intrinsics has %d", timestamps.length, - intrinsics.length / 5)); - } + if ((intrinsics.length / 5) != timestamps.length) { + throw new AssertionError(String.format( + "timestamps has %d entries but intrinsics has %d", timestamps.length, + intrinsics.length / 5)); + } - LensIntrinsicsSample[] samples = new LensIntrinsicsSample[timestamps.length]; - for (int i = 0; i < timestamps.length; i++) { - float[] currentIntrinsic = Arrays.copyOfRange(intrinsics, 5*i, 5*i + 5); - samples[i] = new LensIntrinsicsSample(timestamps[i], currentIntrinsic); + LensIntrinsicsSample[] samples = new LensIntrinsicsSample[timestamps.length]; + for (int i = 0; i < timestamps.length; i++) { + float[] currentIntrinsic = Arrays.copyOfRange(intrinsics, 5 * i, 5 * i + 5); + samples[i] = new LensIntrinsicsSample(timestamps[i], currentIntrinsic); + } + return samples; + } else { + return null; } - return samples; } private Capability[] getExtendedSceneModeCapabilities() { diff --git a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java index 575cbfae34e3..9a4ec5c94b5b 100644 --- a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java +++ b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java @@ -37,16 +37,18 @@ public final class LensIntrinsicsSample { * Create a new {@link LensIntrinsicsSample}. * * <p>{@link LensIntrinsicsSample} contains the timestamp and the - * {@link CaptureResult#LENS_INTRINSIC_CALIBRATION} sample. + * {@link CaptureResult#LENS_INTRINSIC_CALIBRATION} sample.</p> * - * @param timestamp timestamp of the lens intrinsics sample. - * @param lensIntrinsics the lens intrinsic calibration for the sample. + * @param timestampNs timestamp in nanoseconds of the lens intrinsics sample. This uses the + * same time basis as {@link CaptureResult#SENSOR_TIMESTAMP}. + * @param lensIntrinsics the lens {@link CaptureResult#LENS_INTRINSIC_CALIBRATION intrinsic} + * calibration for the sample. * * @throws IllegalArgumentException if lensIntrinsics length is different from 5 */ @FlaggedApi(Flags.FLAG_CONCERT_MODE) - public LensIntrinsicsSample(final long timestamp, @NonNull final float[] lensIntrinsics) { - mTimestampNs = timestamp; + public LensIntrinsicsSample(final long timestampNs, @NonNull final float[] lensIntrinsics) { + mTimestampNs = timestampNs; Preconditions.checkArgument(lensIntrinsics.length == 5); mLensIntrinsics = lensIntrinsics; } @@ -54,18 +56,18 @@ public final class LensIntrinsicsSample { /** * Get the timestamp in nanoseconds. * - *<p>The timestamps are in the same timebase as and comparable to + *<p>The timestamps are in the same time basis as and comparable to *{@link CaptureResult#SENSOR_TIMESTAMP android.sensor.timestamp}.</p> * * @return a long value (guaranteed to be finite) */ @FlaggedApi(Flags.FLAG_CONCERT_MODE) - public long getTimestamp() { + public long getTimestampNanos() { return mTimestampNs; } /** - * Get the lens intrinsics calibration + * Get the lens {@link CaptureResult#LENS_INTRINSIC_CALIBRATION intrinsics} calibration * * @return a floating point value (guaranteed to be finite) * @see CaptureResult#LENS_INTRINSIC_CALIBRATION diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 134a510df5f3..8f0e0c911f56 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -1831,15 +1831,6 @@ public final class DisplayManager { String KEY_POWER_THROTTLING_DATA = "power_throttling_data"; /** - * Key for new power controller feature flag. If enabled new DisplayPowerController will - * be used. - * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)} - * with {@link android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER} as the namespace. - * @hide - */ - String KEY_NEW_POWER_CONTROLLER = "use_newly_structured_display_power_controller"; - - /** * Key for normal brightness mode controller feature flag. * It enables NormalBrightnessModeController. * Read value via {@link android.provider.DeviceConfig#getBoolean(String, String, boolean)} diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 70cf97308ffb..83b7edaec72d 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -80,8 +80,6 @@ public class VcnManager { * <p>The VCN will only migrate to a Carrier WiFi network that has a signal strength greater * than, or equal to this threshold. * - * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. - * * @hide */ @NonNull @@ -94,14 +92,39 @@ public class VcnManager { * <p>If the VCN's selected Carrier WiFi network has a signal strength less than this threshold, * the VCN will attempt to migrate away from the Carrier WiFi network. * - * <p>WARNING: The VCN does not listen for changes to this key made after VCN startup. - * * @hide */ @NonNull public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY = "vcn_network_selection_wifi_exit_rssi_threshold"; + /** + * Key for the interval to poll IpSecTransformState for packet loss monitoring + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY = + "vcn_network_selection_poll_ipsec_state_interval_seconds"; + + /** + * Key for the threshold of IPSec packet loss rate + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY = + "vcn_network_selection_ipsec_packet_loss_percent_threshold"; + + /** + * Key for the list of timeouts in minute to stop penalizing an underlying network candidate + * + * @hide + */ + @NonNull + public static final String VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY = + "vcn_network_selection_penalty_timeout_minutes_list"; + // TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz /** @@ -115,6 +138,20 @@ public class VcnManager { "vcn_restricted_transports"; /** + * Key for number of seconds to wait before entering safe mode + * + * <p>A VcnGatewayConnection will enter safe mode when it takes over the configured timeout to + * enter {@link ConnectedState}. + * + * <p>Defaults to 30, unless overridden by carrier config + * + * @hide + */ + @NonNull + public static final String VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY = + "vcn_safe_mode_timeout_seconds_key"; + + /** * Key for maximum number of parallel SAs for tunnel aggregation * * <p>If set to a value > 1, multiple tunnels will be set up, and inbound traffic will be @@ -134,7 +171,11 @@ public class VcnManager { new String[] { VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY, VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, + VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY, + VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY, }; diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig index 6956916af0f1..7afd72195fcb 100644 --- a/core/java/android/net/vcn/flags.aconfig +++ b/core/java/android/net/vcn/flags.aconfig @@ -5,4 +5,18 @@ flag { namespace: "vcn" description: "Feature flag for safe mode configurability" bug: "276358140" +} + +flag { + name: "safe_mode_timeout_config" + namespace: "vcn" + description: "Feature flag for adjustable safe mode timeout" + bug: "317406085" +} + +flag{ + name: "network_metric_monitor" + namespace: "vcn" + description: "Feature flag for enabling network metric monitor" + bug: "282996138" }
\ No newline at end of file diff --git a/core/java/android/nfc/TEST_MAPPING b/core/java/android/nfc/TEST_MAPPING deleted file mode 100644 index 5b5ea3790010..000000000000 --- a/core/java/android/nfc/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "NfcManagerTests" - }, - { - "name": "CtsNfcTestCases" - } - ] -} diff --git a/core/java/android/nfc/tech/OWNERS b/core/java/android/nfc/tech/OWNERS deleted file mode 100644 index 35e9713f5715..000000000000 --- a/core/java/android/nfc/tech/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# Bug component: 48448 -include platform/packages/apps/Nfc:/OWNERS diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index c60f949da408..fbec518e4a29 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -57,6 +57,7 @@ public final class MessageQueue { @UnsupportedAppUsage Message mMessages; + private Message mLast; @UnsupportedAppUsage private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); private SparseArray<FileDescriptorRecord> mFileDescriptorRecords; @@ -66,6 +67,10 @@ public final class MessageQueue { // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; + // Tracks the number of async message. We use this in enqueueMessage() to avoid searching the + // queue for async messages when inserting a message at the tail. + private int mAsyncMessageCount; + // The next barrier token. // Barriers are indicated by messages with a null target whose arg1 field carries the token. @UnsupportedAppUsage @@ -364,12 +369,21 @@ public final class MessageQueue { mBlocked = false; if (prevMsg != null) { prevMsg.next = msg.next; + if (prevMsg.next == null) { + mLast = prevMsg; + } } else { mMessages = msg.next; + if (msg.next == null) { + mLast = null; + } } msg.next = null; if (DEBUG) Log.v(TAG, "Returning message: " + msg); msg.markInUse(); + if (msg.isAsynchronous()) { + mAsyncMessageCount--; + } return msg; } } else { @@ -492,6 +506,14 @@ public final class MessageQueue { msg.when = when; msg.arg1 = token; + if (Flags.messageQueueTailTracking() && mLast != null && mLast.when <= when) { + /* Message goes to tail of list */ + mLast.next = msg; + mLast = msg; + msg.next = null; + return token; + } + Message prev = null; Message p = mMessages; if (when != 0) { @@ -500,6 +522,12 @@ public final class MessageQueue { p = p.next; } } + + if (p == null) { + /* We reached the tail of the list, or list is empty. */ + mLast = msg; + } + if (prev != null) { // invariant: p == prev.next msg.next = p; prev.next = msg; @@ -540,9 +568,15 @@ public final class MessageQueue { final boolean needWake; if (prev != null) { prev.next = p.next; + if (prev.next == null) { + mLast = prev; + } needWake = false; } else { mMessages = p.next; + if (mMessages == null) { + mLast = null; + } needWake = mMessages == null || mMessages.target != null; } p.recycleUnchecked(); @@ -582,24 +616,77 @@ public final class MessageQueue { msg.next = p; mMessages = msg; needWake = mBlocked; + if (p == null) { + mLast = mMessages; + } } else { - // Inserted within the middle of the queue. Usually we don't have to wake - // up the event queue unless there is a barrier at the head of the queue - // and the message is the earliest asynchronous message in the queue. - needWake = mBlocked && p.target == null && msg.isAsynchronous(); - Message prev; - for (;;) { - prev = p; - p = p.next; - if (p == null || when < p.when) { - break; + // Message is to be inserted at tail or middle of queue. Usually we don't have to + // wake up the event queue unless there is a barrier at the head of the queue and + // the message is the earliest asynchronous message in the queue. + // + // For readability, we split this portion of the function into two blocks based on + // whether tail tracking is enabled. This has a minor implication for the case + // where tail tracking is disabled. See the comment below. + if (Flags.messageQueueTailTracking()) { + needWake = mBlocked && p.target == null && msg.isAsynchronous() + && mAsyncMessageCount == 0; + if (when >= mLast.when) { + msg.next = null; + mLast.next = msg; + mLast = msg; + } else { + // Inserted within the middle of the queue. + Message prev; + for (;;) { + prev = p; + p = p.next; + if (p == null || when < p.when) { + break; + } + } + if (p == null) { + /* Inserting at tail of queue */ + mLast = msg; + } + msg.next = p; // invariant: p == prev.next + prev.next = msg; } - if (needWake && p.isAsynchronous()) { - needWake = false; + } else { + needWake = mBlocked && p.target == null && msg.isAsynchronous(); + Message prev; + for (;;) { + prev = p; + p = p.next; + if (p == null || when < p.when) { + break; + } + if (needWake && p.isAsynchronous()) { + needWake = false; + } } + msg.next = p; // invariant: p == prev.next + prev.next = msg; + + /* + * If this block is executing then we have a build without tail tracking - + * specifically: Flags.messageQueueTailTracking() == false. This is determined + * at build time so the flag won't change on us during runtime. + * + * Since we don't want to pepper the code with extra checks, we only check + * for tail tracking when we might use mLast. Otherwise, we continue to update + * mLast as the tail of the list. + * + * In this case however we are not maintaining mLast correctly. Since we never + * use it, this is fine. However, we run the risk of leaking a reference. + * So set mLast to null in this case to avoid any Message leaks. The other + * sites will never use the value so we are safe against null pointer derefs. + */ + mLast = null; } - msg.next = p; // invariant: p == prev.next - prev.next = msg; + } + + if (msg.isAsynchronous()) { + mAsyncMessageCount++; } // We can assume mPtr != 0 because mQuitting is false. @@ -692,10 +779,17 @@ public final class MessageQueue { && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; @@ -703,8 +797,14 @@ public final class MessageQueue { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -726,10 +826,17 @@ public final class MessageQueue { && (object == null || object.equals(p.obj))) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; @@ -737,8 +844,14 @@ public final class MessageQueue { if (n.target == h && n.what == what && (object == null || object.equals(n.obj))) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -760,10 +873,17 @@ public final class MessageQueue { && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; @@ -771,8 +891,14 @@ public final class MessageQueue { if (n.target == h && n.callback == r && (object == null || n.obj == object)) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -794,10 +920,17 @@ public final class MessageQueue { && (object == null || object.equals(p.obj))) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; @@ -805,8 +938,14 @@ public final class MessageQueue { if (n.target == h && n.callback == r && (object == null || object.equals(n.obj))) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -829,18 +968,31 @@ public final class MessageQueue { && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -862,18 +1014,31 @@ public final class MessageQueue { && (object == null || object.equals(p.obj))) { Message n = p.next; mMessages = n; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); p = n; } + if (p == null) { + mLast = mMessages; + } + // Remove all messages after front. while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || object.equals(n.obj))) { Message nn = n.next; + if (n.isAsynchronous()) { + mAsyncMessageCount--; + } n.recycleUnchecked(); p.next = nn; + if (p.next == null) { + mLast = p; + } continue; } } @@ -890,6 +1055,8 @@ public final class MessageQueue { p = n; } mMessages = null; + mLast = null; + mAsyncMessageCount = 0; } private void removeAllFutureMessagesLocked() { @@ -911,9 +1078,14 @@ public final class MessageQueue { p = n; } p.next = null; + mLast = p; + do { p = n; n = p.next; + if (p.isAsynchronous()) { + mAsyncMessageCount--; + } p.recycleUnchecked(); } while (n != null); } diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java index 37bde3db5e14..746278fc296c 100644 --- a/core/java/android/os/PerformanceHintManager.java +++ b/core/java/android/os/PerformanceHintManager.java @@ -204,7 +204,7 @@ public final class PerformanceHintManager { } /** - * Updates this session's target duration for each cycle of work. + * Updates this session's target total duration for each cycle of work. * * @param targetDurationNanos the new desired duration in nanoseconds */ diff --git a/core/java/android/os/PowerMonitorReadings.java b/core/java/android/os/PowerMonitorReadings.java index bb677d529507..a0ab066ffb75 100644 --- a/core/java/android/os/PowerMonitorReadings.java +++ b/core/java/android/os/PowerMonitorReadings.java @@ -71,7 +71,7 @@ public final class PowerMonitorReadings { */ @FlaggedApi("com.android.server.power.optimization.power_monitor_api") @ElapsedRealtimeLong - public long getTimestamp(@NonNull PowerMonitor powerMonitor) { + public long getTimestampMillis(@NonNull PowerMonitor powerMonitor) { int offset = Arrays.binarySearch(mPowerMonitors, powerMonitor, POWER_MONITOR_COMPARATOR); if (offset >= 0) { return mTimestampsMs[offset]; diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index f952fcf36e60..dd0436cbb2f2 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -19,6 +19,7 @@ package android.os; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import android.annotation.ElapsedRealtimeLong; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -37,6 +38,7 @@ import android.webkit.WebViewZygote; import com.android.internal.os.SomeArgs; import com.android.internal.util.Preconditions; +import com.android.sdksandbox.flags.Flags; import dalvik.system.VMRuntime; @@ -1016,11 +1018,30 @@ public class Process { @SystemApi(client = MODULE_LIBRARIES) @TestApi @android.ravenwood.annotation.RavenwoodKeep + // TODO(b/318651609): Deprecate once Process#getSdkSandboxUidForAppUid is rolled out to 100% public static final int toSdkSandboxUid(int uid) { return uid + (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID); } /** + * Returns the sdk sandbox uid corresponding to an app uid. + * @see android.app.sdksandbox.SdkSandboxManager + * + * @param uid the app uid + * @return the sdk sandbox uid for the given app uid + * + * @throws IllegalArgumentException if input is not an app uid + */ + @FlaggedApi(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API) + @android.ravenwood.annotation.RavenwoodKeep + public static final int getSdkSandboxUidForAppUid(int uid) { + if (!isApplicationUid(uid)) { + throw new IllegalArgumentException("Input UID is not an app UID"); + } + return uid + (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID); + } + + /** * Returns whether the current process is a sdk sandbox process. */ @android.ravenwood.annotation.RavenwoodKeep diff --git a/core/java/android/os/WorkDuration.java b/core/java/android/os/WorkDuration.java index 4fdc34fb60d1..2ebcd830be29 100644 --- a/core/java/android/os/WorkDuration.java +++ b/core/java/android/os/WorkDuration.java @@ -26,7 +26,7 @@ import java.util.Objects; * in each component, see * {@link PerformanceHintManager.Session#reportActualWorkDuration(WorkDuration)}. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()} and measured in wall time. */ @FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) public final class WorkDuration implements Parcelable { @@ -50,17 +50,9 @@ public final class WorkDuration implements Parcelable { public WorkDuration() {} - public WorkDuration(long workPeriodStartTimestampNanos, - long actualTotalDurationNanos, - long actualCpuDurationNanos, - long actualGpuDurationNanos) { - mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos; - mActualTotalDurationNanos = actualTotalDurationNanos; - mActualCpuDurationNanos = actualCpuDurationNanos; - mActualGpuDurationNanos = actualGpuDurationNanos; - } - /** + * Constructor for testing. + * * @hide */ public WorkDuration(long workPeriodStartTimestampNanos, @@ -86,7 +78,7 @@ public final class WorkDuration implements Parcelable { /** * Sets the work period start timestamp in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public void setWorkPeriodStartTimestampNanos(long workPeriodStartTimestampNanos) { if (workPeriodStartTimestampNanos <= 0) { @@ -99,7 +91,7 @@ public final class WorkDuration implements Parcelable { /** * Sets the actual total duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public void setActualTotalDurationNanos(long actualTotalDurationNanos) { if (actualTotalDurationNanos <= 0) { @@ -111,7 +103,7 @@ public final class WorkDuration implements Parcelable { /** * Sets the actual CPU duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public void setActualCpuDurationNanos(long actualCpuDurationNanos) { if (actualCpuDurationNanos <= 0) { @@ -123,7 +115,7 @@ public final class WorkDuration implements Parcelable { /** * Sets the actual GPU duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public void setActualGpuDurationNanos(long actualGpuDurationNanos) { if (actualGpuDurationNanos < 0) { @@ -135,7 +127,7 @@ public final class WorkDuration implements Parcelable { /** * Returns the work period start timestamp based in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public long getWorkPeriodStartTimestampNanos() { return mWorkPeriodStartTimestampNanos; @@ -144,7 +136,7 @@ public final class WorkDuration implements Parcelable { /** * Returns the actual total duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public long getActualTotalDurationNanos() { return mActualTotalDurationNanos; @@ -153,7 +145,7 @@ public final class WorkDuration implements Parcelable { /** * Returns the actual CPU duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public long getActualCpuDurationNanos() { return mActualCpuDurationNanos; @@ -162,7 +154,7 @@ public final class WorkDuration implements Parcelable { /** * Returns the actual GPU duration in nanoseconds. * - * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}. + * All timings should be in {@link SystemClock#uptimeNanos()}. */ public long getActualGpuDurationNanos() { return mActualGpuDurationNanos; diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index d64614628b61..0db90bff48fd 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -98,3 +98,11 @@ flag { description: "Guards StrictMode APIs for detecting restricted network access." bug: "317250784" } + +flag { + name: "message_queue_tail_tracking" + namespace: "system_performance" + description: "track tail of message queue." + bug: "305311707" + is_fixed_read_only: true +} diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index 2d53341be654..322a8e62dbb3 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -25,8 +25,8 @@ import android.content.Context; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; -import android.os.Handler; import android.os.IPowerStatsService; +import android.os.OutcomeReceiver; import android.os.PowerMonitor; import android.os.PowerMonitorReadings; import android.os.Process; @@ -39,6 +39,7 @@ import com.android.internal.app.IBatteryStats; import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -161,12 +162,12 @@ public class SystemHealthManager { * (on-device power rail monitor) rails and modeled energy consumers. If ODPM is unsupported * on this device this method delivers an empty list. * - * @param handler optional Handler to deliver the callback. If not supplied, the callback + * @param executor optional Handler to deliver the callback. If not supplied, the callback * may be invoked on an arbitrary thread. * @param onResult callback for the result */ @FlaggedApi("com.android.server.power.optimization.power_monitor_api") - public void getSupportedPowerMonitors(@Nullable Handler handler, + public void getSupportedPowerMonitors(@Nullable Executor executor, @NonNull Consumer<List<PowerMonitor>> onResult) { final List<PowerMonitor> result; synchronized (mPowerMonitorsLock) { @@ -180,15 +181,15 @@ public class SystemHealthManager { } } if (result != null) { - if (handler != null) { - handler.post(() -> onResult.accept(result)); + if (executor != null) { + executor.execute(() -> onResult.accept(result)); } else { onResult.accept(result); } return; } try { - mPowerStats.getSupportedPowerMonitors(new ResultReceiver(handler) { + mPowerStats.getSupportedPowerMonitors(new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { PowerMonitor[] array = resultData.getParcelableArray( @@ -197,7 +198,11 @@ public class SystemHealthManager { synchronized (mPowerMonitorsLock) { mPowerMonitorsInfo = result; } - onResult.accept(result); + if (executor != null) { + executor.execute(()-> onResult.accept(result)); + } else { + onResult.accept(result); + } } }); } catch (RemoteException e) { @@ -213,17 +218,22 @@ public class SystemHealthManager { * monitors. * * @param powerMonitors power monitors to be retrieved. - * @param handler optional Handler to deliver the callbacks. If not supplied, the callback - * may be invoked on an arbitrary thread. - * @param onSuccess callback for the result - * @param onError callback invoked in case of an error + * @param executor optional Executor to deliver the callbacks. If not supplied, the + * callback may be invoked on an arbitrary thread. + * @param onResult callback for the result */ @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull List<PowerMonitor> powerMonitors, - @Nullable Handler handler, @NonNull Consumer<PowerMonitorReadings> onSuccess, - @NonNull Consumer<RuntimeException> onError) { + @Nullable Executor executor, + @NonNull OutcomeReceiver<PowerMonitorReadings, RuntimeException> onResult) { if (mPowerStats == null) { - onError.accept(new IllegalArgumentException("Unsupported power monitor")); + IllegalArgumentException error = + new IllegalArgumentException("Unsupported power monitor"); + if (executor != null) { + executor.execute(() -> onResult.onError(error)); + } else { + onResult.onError(error); + } return; } @@ -235,18 +245,31 @@ public class SystemHealthManager { indices[i] = powerMonitorsArray[i].index; } try { - mPowerStats.getPowerMonitorReadings(indices, new ResultReceiver(handler) { + mPowerStats.getPowerMonitorReadings(indices, new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == IPowerStatsService.RESULT_SUCCESS) { - onSuccess.accept(new PowerMonitorReadings(powerMonitorsArray, + PowerMonitorReadings result = new PowerMonitorReadings(powerMonitorsArray, resultData.getLongArray(IPowerStatsService.KEY_ENERGY), - resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS))); - } else if (resultCode == IPowerStatsService.RESULT_UNSUPPORTED_POWER_MONITOR) { - onError.accept(new IllegalArgumentException("Unsupported power monitor")); + resultData.getLongArray(IPowerStatsService.KEY_TIMESTAMPS)); + if (executor != null) { + executor.execute(() -> onResult.onResult(result)); + } else { + onResult.onResult(result); + } } else { - onError.accept(new IllegalStateException( - "Unrecognized result code " + resultCode)); + RuntimeException error; + if (resultCode == IPowerStatsService.RESULT_UNSUPPORTED_POWER_MONITOR) { + error = new IllegalArgumentException("Unsupported power monitor"); + } else { + error = new IllegalStateException( + "Unrecognized result code " + resultCode); + } + if (executor != null) { + executor.execute(() -> onResult.onError(error)); + } else { + onResult.onError(error); + } } } }); diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index fae7cb394906..60143cc79d2d 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -71,3 +71,10 @@ flag { description: "default retail demo role holder" bug: "274132354" } + +flag { + name: "wallet_role_enabled" + namespace: "wallet_integration" + description: "This flag is used to enabled the Wallet Role for all users on the device" + bug: "283989236" +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 18040b7b1270..f974ef43a9dc 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -108,7 +108,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -3586,10 +3585,12 @@ public final class Settings { || applicationInfo.isSignedWithPlatformKey(); } - public ArrayMap<String, String> getStringsForPrefix(ContentResolver cr, String prefix, - List<String> names) { + private ArrayMap<String, String> getStringsForPrefixStripPrefix( + ContentResolver cr, String prefix, String[] names) { String namespace = prefix.substring(0, prefix.length() - 1); ArrayMap<String, String> keyValues = new ArrayMap<>(); + int substringLength = prefix.length(); + int currentGeneration = -1; boolean needsGenerationTracker = false; @@ -3619,10 +3620,13 @@ public final class Settings { if (DEBUG) { Log.i(TAG, "Cache hit for prefix:" + prefix); } - if (!names.isEmpty()) { + if (names.length > 0) { for (String name : names) { + // mValues can contain "null" values, need to use containsKey. if (mValues.containsKey(name)) { - keyValues.put(name, mValues.get(name)); + keyValues.put( + name.substring(substringLength), + mValues.get(name)); } } } else { @@ -3631,7 +3635,10 @@ public final class Settings { // Explicitly exclude the prefix as it is only there to // signal that the prefix has been cached. if (key.startsWith(prefix) && !key.equals(prefix)) { - keyValues.put(key, mValues.get(key)); + String value = mValues.valueAt(i); + keyValues.put( + key.substring(substringLength), + value); } } } @@ -3691,14 +3698,22 @@ public final class Settings { Map<String, String> flagsToValues = (HashMap) b.getSerializable(Settings.NameValueTable.VALUE, java.util.HashMap.class); // Only the flags requested by the caller - if (!names.isEmpty()) { - for (Map.Entry<String, String> flag : flagsToValues.entrySet()) { - if (names.contains(flag.getKey())) { - keyValues.put(flag.getKey(), flag.getValue()); + if (names.length > 0) { + for (String name : names) { + // flagsToValues can contain "null" values, need to use containsKey. + if (flagsToValues.containsKey(name)) { + keyValues.put( + name.substring(substringLength), + flagsToValues.get(name)); } } } else { - keyValues.putAll(flagsToValues); + keyValues.ensureCapacity(keyValues.size() + flagsToValues.size()); + for (Map.Entry<String, String> flag : flagsToValues.entrySet()) { + keyValues.put( + flag.getKey().substring(substringLength), + flag.getValue()); + } } synchronized (NameValueCache.this) { @@ -10143,8 +10158,12 @@ public final class Settings { /** * The default NFC payment component + * + * @deprecated please use {@link android.app.role.RoleManager#getRoleHolders(String)} + * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter. * @hide */ + @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; @@ -12161,6 +12180,36 @@ public final class Settings { */ public static final String HIDE_PRIVATESPACE_ENTRY_POINT = "hide_privatespace_entry_point"; + /** @hide */ + public static final int PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK = 0; + /** @hide */ + public static final int PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY = 1; + /** @hide */ + public static final int PRIVATE_SPACE_AUTO_LOCK_NEVER = 2; + + /** + * The different auto lock options for private space. + * + * @hide + */ + @IntDef(prefix = {"PRIVATE_SPACE_AUTO_LOCK_"}, value = { + PRIVATE_SPACE_AUTO_LOCK_ON_DEVICE_LOCK, + PRIVATE_SPACE_AUTO_LOCK_AFTER_INACTIVITY, + PRIVATE_SPACE_AUTO_LOCK_NEVER, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface PrivateSpaceAutoLockOption { + } + + + /** + * Store auto lock value for private space. + * The possible values are defined in {@link PrivateSpaceAutoLockOption}. + * + * @hide + */ + public static final String PRIVATE_SPACE_AUTO_LOCK = "private_space_auto_lock"; + /** * These entries are considered common between the personal and the managed profile, * since the managed profile doesn't get to change them. @@ -13427,6 +13476,16 @@ public final class Settings { @Readable public static final String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; + + /** + * Whether to boot with 16K page size compatible kernel + * 1 = Boot with 16K kernel + * 0 = Boot with 4K kernel (default) + * @hide + */ + @Readable + public static final String ENABLE_16K_PAGES = "enable_16k_pages"; + /** Timeout for package verification. * @hide */ @Readable @@ -19850,21 +19909,15 @@ public final class Settings { @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) public static Map<String, String> getStrings(@NonNull ContentResolver resolver, @NonNull String namespace, @NonNull List<String> names) { - List<String> compositeNames = new ArrayList<>(names.size()); - for (String name : names) { - compositeNames.add(createCompositeName(namespace, name)); + String[] compositeNames = new String[names.size()]; + for (int i = 0, size = names.size(); i < size; ++i) { + compositeNames[i] = createCompositeName(namespace, names.get(i)); } String prefix = createPrefix(namespace); - ArrayMap<String, String> rawKeyValues = sNameValueCache.getStringsForPrefix( + + ArrayMap<String, String> keyValues = sNameValueCache.getStringsForPrefixStripPrefix( resolver, prefix, compositeNames); - int size = rawKeyValues.size(); - int substringLength = prefix.length(); - ArrayMap<String, String> keyValues = new ArrayMap<>(size); - for (int i = 0; i < size; ++i) { - keyValues.put(rawKeyValues.keyAt(i).substring(substringLength), - rawKeyValues.valueAt(i)); - } return keyValues; } @@ -20190,12 +20243,13 @@ public final class Settings { private static String createCompositeName(@NonNull String namespace, @NonNull String name) { Preconditions.checkNotNull(namespace); Preconditions.checkNotNull(name); - return createPrefix(namespace) + name; + var sb = new StringBuilder(namespace.length() + 1 + name.length()); + return sb.append(namespace).append('/').append(name).toString(); } private static String createPrefix(@NonNull String namespace) { Preconditions.checkNotNull(namespace); - return namespace + "/"; + return namespace + '/'; } private static Uri createNamespaceUri(@NonNull String namespace) { diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 7d9c0a37a13f..2d657c2813a5 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -445,6 +445,19 @@ public class DreamService extends Service implements Window.Callback { } /** + * Retrieves the current {@link android.app.Activity} associated with the dream. + * This method behaves similarly to calling {@link android.app.Activity#getActivity()}. + * + * @return The current activity, or null if the dream is not associated with an activity + * or not started. + * + * @hide + */ + public Activity getActivity() { + return mActivity; + } + + /** * Inflates a layout resource and set it to be the content view for this Dream. * Behaves similarly to {@link android.app.Activity#setContentView(int)}. * diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 92c516c38dcc..7658af53a7f8 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -42,6 +42,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.os.BadParcelableException; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -1056,7 +1057,7 @@ public abstract class NotificationListenerService extends Service { ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface() .getActiveNotificationsFromListener(mWrapper, keys, trim); return cleanUpNotificationList(parceledList); - } catch (android.os.RemoteException ex) { + } catch (android.os.RemoteException | BadParcelableException ex) { Log.v(TAG, "Unable to contact notification manager", ex); } return null; diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 45a0c205a09b..54248be74e04 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -64,6 +64,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.Instant; import java.util.Arrays; import java.util.Calendar; import java.util.Date; @@ -233,6 +234,7 @@ public class ZenModeConfig implements Parcelable { private static final String MANUAL_TAG = "manual"; private static final String AUTOMATIC_TAG = "automatic"; + private static final String AUTOMATIC_DELETED_TAG = "deleted"; private static final String RULE_ATT_ID = "ruleId"; private static final String RULE_ATT_ENABLED = "enabled"; @@ -251,6 +253,7 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_USER_MODIFIED_FIELDS = "userModifiedFields"; private static final String RULE_ATT_ICON = "rule_icon"; private static final String RULE_ATT_TRIGGER_DESC = "triggerDesc"; + private static final String RULE_ATT_DELETION_INSTANT = "deletionInstant"; private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale"; private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY = @@ -292,6 +295,10 @@ public class ZenModeConfig implements Parcelable { @UnsupportedAppUsage public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>(); + // Note: Map is *pkg|conditionId* (see deletedRuleKey()) -> ZenRule, + // unlike automaticRules (which is id -> rule). + public final ArrayMap<String, ZenRule> deletedRules = new ArrayMap<>(); + @UnsupportedAppUsage public ZenModeConfig() { } @@ -306,15 +313,9 @@ public class ZenModeConfig implements Parcelable { allowMessagesFrom = source.readInt(); user = source.readInt(); manualRule = source.readParcelable(null, ZenRule.class); - final int len = source.readInt(); - if (len > 0) { - final String[] ids = new String[len]; - final ZenRule[] rules = new ZenRule[len]; - source.readStringArray(ids); - source.readTypedArray(rules, ZenRule.CREATOR); - for (int i = 0; i < len; i++) { - automaticRules.put(ids[i], rules[i]); - } + readRulesFromParcel(automaticRules, source); + if (Flags.modesApi()) { + readRulesFromParcel(deletedRules, source); } allowAlarms = source.readInt() == 1; allowMedia = source.readInt() == 1; @@ -328,6 +329,19 @@ public class ZenModeConfig implements Parcelable { } } + private static void readRulesFromParcel(ArrayMap<String, ZenRule> ruleMap, Parcel source) { + final int len = source.readInt(); + if (len > 0) { + final String[] ids = new String[len]; + final ZenRule[] rules = new ZenRule[len]; + source.readStringArray(ids); + source.readTypedArray(rules, ZenRule.CREATOR); + for (int i = 0; i < len; i++) { + ruleMap.put(ids[i], rules[i]); + } + } + } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(allowCalls ? 1 : 0); @@ -339,19 +353,9 @@ public class ZenModeConfig implements Parcelable { dest.writeInt(allowMessagesFrom); dest.writeInt(user); dest.writeParcelable(manualRule, 0); - if (!automaticRules.isEmpty()) { - final int len = automaticRules.size(); - final String[] ids = new String[len]; - final ZenRule[] rules = new ZenRule[len]; - for (int i = 0; i < len; i++) { - ids[i] = automaticRules.keyAt(i); - rules[i] = automaticRules.valueAt(i); - } - dest.writeInt(len); - dest.writeStringArray(ids); - dest.writeTypedArray(rules, 0); - } else { - dest.writeInt(0); + writeRulesToParcel(automaticRules, dest); + if (Flags.modesApi()) { + writeRulesToParcel(deletedRules, dest); } dest.writeInt(allowAlarms ? 1 : 0); dest.writeInt(allowMedia ? 1 : 0); @@ -365,6 +369,23 @@ public class ZenModeConfig implements Parcelable { } } + private static void writeRulesToParcel(ArrayMap<String, ZenRule> ruleMap, Parcel dest) { + if (!ruleMap.isEmpty()) { + final int len = ruleMap.size(); + final String[] ids = new String[len]; + final ZenRule[] rules = new ZenRule[len]; + for (int i = 0; i < len; i++) { + ids[i] = ruleMap.keyAt(i); + rules[i] = ruleMap.valueAt(i); + } + dest.writeInt(len); + dest.writeStringArray(ids); + dest.writeTypedArray(rules, 0); + } else { + dest.writeInt(0); + } + } + @Override public String toString() { StringBuilder sb = new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[') @@ -389,23 +410,26 @@ public class ZenModeConfig implements Parcelable { } else { sb.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd); } - return sb.append(",\nautomaticRules=").append(rulesToString()) - .append(",\nmanualRule=").append(manualRule) - .append(']').toString(); + sb.append(",\nautomaticRules=").append(rulesToString(automaticRules)) + .append(",\nmanualRule=").append(manualRule); + if (Flags.modesApi()) { + sb.append(",\ndeletedRules=").append(rulesToString(deletedRules)); + } + return sb.append(']').toString(); } - private String rulesToString() { - if (automaticRules.isEmpty()) { + private static String rulesToString(ArrayMap<String, ZenRule> ruleList) { + if (ruleList.isEmpty()) { return "{}"; } - StringBuilder buffer = new StringBuilder(automaticRules.size() * 28); + StringBuilder buffer = new StringBuilder(ruleList.size() * 28); buffer.append("{\n"); - for (int i = 0; i < automaticRules.size(); i++) { + for (int i = 0; i < ruleList.size(); i++) { if (i > 0) { buffer.append(",\n"); } - Object value = automaticRules.valueAt(i); + Object value = ruleList.valueAt(i); buffer.append(value); } buffer.append('}'); @@ -487,7 +511,9 @@ public class ZenModeConfig implements Parcelable { && other.allowConversations == allowConversations && other.allowConversationsFrom == allowConversationsFrom; if (Flags.modesApi()) { - return eq && other.allowPriorityChannels == allowPriorityChannels; + return eq + && Objects.equals(other.deletedRules, deletedRules) + && other.allowPriorityChannels == allowPriorityChannels; } return eq; } @@ -644,12 +670,20 @@ public class ZenModeConfig implements Parcelable { DEFAULT_SUPPRESSED_VISUAL_EFFECTS); } else if (MANUAL_TAG.equals(tag)) { rt.manualRule = readRuleXml(parser); - } else if (AUTOMATIC_TAG.equals(tag)) { + } else if (AUTOMATIC_TAG.equals(tag) + || (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag))) { final String id = parser.getAttributeValue(null, RULE_ATT_ID); final ZenRule automaticRule = readRuleXml(parser); if (id != null && automaticRule != null) { automaticRule.id = id; - rt.automaticRules.put(id, automaticRule); + if (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag)) { + String deletedRuleKey = deletedRuleKey(automaticRule); + if (deletedRuleKey != null) { + rt.deletedRules.put(deletedRuleKey, automaticRule); + } + } else if (AUTOMATIC_TAG.equals(tag)) { + rt.automaticRules.put(id, automaticRule); + } } } else if (STATE_TAG.equals(tag)) { rt.areChannelsBypassingDnd = safeBoolean(parser, @@ -660,13 +694,24 @@ public class ZenModeConfig implements Parcelable { throw new IllegalStateException("Failed to reach END_DOCUMENT"); } + /** Generates the map key used for a {@link ZenRule} in {@link #deletedRules}. */ + @Nullable + public static String deletedRuleKey(ZenRule rule) { + if (rule.pkg != null && rule.conditionId != null) { + return rule.pkg + "|" + rule.conditionId.toString(); + } else { + return null; + } + } + /** * Writes XML of current ZenModeConfig * @param out serializer * @param version uses XML_VERSION if version is null * @throws IOException */ - public void writeXml(TypedXmlSerializer out, Integer version) throws IOException { + public void writeXml(TypedXmlSerializer out, Integer version, boolean forBackup) + throws IOException { out.startTag(null, ZEN_TAG); out.attribute(null, ZEN_ATT_VERSION, version == null ? Integer.toString(XML_VERSION) : Integer.toString(version)); @@ -707,6 +752,15 @@ public class ZenModeConfig implements Parcelable { writeRuleXml(automaticRule, out); out.endTag(null, AUTOMATIC_TAG); } + if (Flags.modesApi() && !forBackup) { + for (int i = 0; i < deletedRules.size(); i++) { + final ZenRule deletedRule = deletedRules.valueAt(i); + out.startTag(null, AUTOMATIC_DELETED_TAG); + out.attribute(null, RULE_ATT_ID, deletedRule.id); + writeRuleXml(deletedRule, out); + out.endTag(null, AUTOMATIC_DELETED_TAG); + } + } out.startTag(null, STATE_TAG); out.attributeBoolean(null, STATE_ATT_CHANNELS_BYPASSING_DND, areChannelsBypassingDnd); @@ -752,6 +806,11 @@ public class ZenModeConfig implements Parcelable { rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC); rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN); rt.userModifiedFields = safeInt(parser, RULE_ATT_USER_MODIFIED_FIELDS, 0); + Long deletionInstant = tryParseLong( + parser.getAttributeValue(null, RULE_ATT_DELETION_INSTANT), null); + if (deletionInstant != null) { + rt.deletionInstant = Instant.ofEpochMilli(deletionInstant); + } } return rt; } @@ -799,6 +858,10 @@ public class ZenModeConfig implements Parcelable { } out.attributeInt(null, RULE_ATT_TYPE, rule.type); out.attributeInt(null, RULE_ATT_USER_MODIFIED_FIELDS, rule.userModifiedFields); + if (rule.deletionInstant != null) { + out.attributeLong(null, RULE_ATT_DELETION_INSTANT, + rule.deletionInstant.toEpochMilli()); + } } } @@ -1998,6 +2061,7 @@ public class ZenModeConfig implements Parcelable { public String iconResName; public boolean allowManualInvocation; public int userModifiedFields; + @Nullable public Instant deletionInstant; // Only set on deleted rules. public ZenRule() { } @@ -2031,6 +2095,9 @@ public class ZenModeConfig implements Parcelable { triggerDescription = source.readString(); type = source.readInt(); userModifiedFields = source.readInt(); + if (source.readInt() == 1) { + deletionInstant = Instant.ofEpochMilli(source.readLong()); + } } } @@ -2091,6 +2158,12 @@ public class ZenModeConfig implements Parcelable { dest.writeString(triggerDescription); dest.writeInt(type); dest.writeInt(userModifiedFields); + if (deletionInstant != null) { + dest.writeInt(1); + dest.writeLong(deletionInstant.toEpochMilli()); + } else { + dest.writeInt(0); + } } } @@ -2121,6 +2194,9 @@ public class ZenModeConfig implements Parcelable { .append(",triggerDescription=").append(triggerDescription) .append(",type=").append(type) .append(",userModifiedFields=").append(userModifiedFields); + if (deletionInstant != null) { + sb.append(",deletionInstant=").append(deletionInstant); + } } return sb.append(']').toString(); @@ -2180,7 +2256,8 @@ public class ZenModeConfig implements Parcelable { && Objects.equals(other.iconResName, iconResName) && Objects.equals(other.triggerDescription, triggerDescription) && other.type == type - && other.userModifiedFields == userModifiedFields; + && other.userModifiedFields == userModifiedFields + && Objects.equals(other.deletionInstant, deletionInstant); } return finalEquals; @@ -2192,7 +2269,7 @@ public class ZenModeConfig implements Parcelable { return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, component, configurationActivity, pkg, id, enabler, zenPolicy, zenDeviceEffects, modified, allowManualInvocation, iconResName, - triggerDescription, type, userModifiedFields); + triggerDescription, type, userModifiedFields, deletionInstant); } return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition, component, configurationActivity, pkg, id, enabler, zenPolicy, modified); diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java index 8902368072bf..91ef11cf1d2d 100644 --- a/core/java/android/service/notification/ZenModeDiff.java +++ b/core/java/android/service/notification/ZenModeDiff.java @@ -30,6 +30,11 @@ import java.util.Set; /** * ZenModeDiff is a utility class meant to encapsulate the diff between ZenModeConfigs and their * subcomponents (automatic and manual ZenRules). + * + * <p>Note that this class is intended to detect <em>meaningful</em> differences, so objects that + * are not identical (as per their {@code equals()} implementation) can still produce an empty diff + * if only "metadata" fields are updated. + * * @hide */ public class ZenModeDiff { @@ -467,7 +472,6 @@ public class ZenModeDiff { public static final String FIELD_ICON_RES = "iconResName"; public static final String FIELD_TRIGGER_DESCRIPTION = "triggerDescription"; public static final String FIELD_TYPE = "type"; - public static final String FIELD_USER_MODIFIED_FIELDS = "userModifiedFields"; // NOTE: new field strings must match the variable names in ZenModeConfig.ZenRule // Special field to track whether this rule became active or inactive @@ -563,10 +567,6 @@ public class ZenModeDiff { if (!Objects.equals(from.iconResName, to.iconResName)) { addField(FIELD_ICON_RES, new FieldDiff<>(from.iconResName, to.iconResName)); } - if (from.userModifiedFields != to.userModifiedFields) { - addField(FIELD_USER_MODIFIED_FIELDS, - new FieldDiff<>(from.userModifiedFields, to.userModifiedFields)); - } } } diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig index a2ade6a9473f..3008b8d45252 100644 --- a/core/java/android/service/notification/flags.aconfig +++ b/core/java/android/service/notification/flags.aconfig @@ -21,3 +21,11 @@ flag { description: "This flag controls the redacting of sensitive notifications from untrusted NotificationListenerServices" bug: "306271190" } + +flag { + name: "callstyle_callback_api" + namespace: "systemui" + description: "Guards the new CallStyleNotificationEventsCallback" + bug: "305095040" + is_fixed_read_only: true +}
\ No newline at end of file diff --git a/core/java/android/service/wearable/OWNERS b/core/java/android/service/wearable/OWNERS index 073e2d79850b..eca48b742cef 100644 --- a/core/java/android/service/wearable/OWNERS +++ b/core/java/android/service/wearable/OWNERS @@ -1,3 +1 @@ -charliewang@google.com -oni@google.com -volnov@google.com
\ No newline at end of file +include /core/java/android/app/wearable/OWNERS
\ No newline at end of file diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java index 118d0284fb9e..1ca7ac77158c 100644 --- a/core/java/android/speech/RecognizerIntent.java +++ b/core/java/android/speech/RecognizerIntent.java @@ -16,6 +16,9 @@ package android.speech; +import static android.speech.flags.Flags.FLAG_MULTILANG_EXTRA_LAUNCH; + +import android.annotation.FlaggedApi; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; @@ -653,4 +656,30 @@ public class RecognizerIntent { */ public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES = "android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES"; + + /** + * Optional integer to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}. If set, the language + * switch will be deactivated when LANGUAGE_SWITCH_MAX_SWITCHES reached. + * + * <p> Depending on the recognizer implementation, this flag may have no effect. + * + * @see #EXTRA_ENABLE_LANGUAGE_SWITCH + */ + @FlaggedApi(FLAG_MULTILANG_EXTRA_LAUNCH) + public static final String EXTRA_LANGUAGE_SWITCH_MAX_SWITCHES = + "android.speech.extra.LANGUAGE_SWITCH_MAX_SWITCHES"; + + /** + * Optional integer to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}. If set, the language + * switch will only be activated for this value of ms of audio since the START_OF_SPEECH. This + * could provide a more stable recognition result when the language switch is only required in + * the beginning of the session. + * + * <p> Depending on the recognizer implementation, this flag may have no effect. + * + * @see #EXTRA_ENABLE_LANGUAGE_SWITCH + */ + @FlaggedApi(FLAG_MULTILANG_EXTRA_LAUNCH) + public static final String EXTRA_LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS = + "android.speech.extra.LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS"; } diff --git a/core/java/android/speech/flags/speech_flags.aconfig b/core/java/android/speech/flags/speech_flags.aconfig new file mode 100644 index 000000000000..fd8012746a27 --- /dev/null +++ b/core/java/android/speech/flags/speech_flags.aconfig @@ -0,0 +1,8 @@ +package: "android.speech.flags" + +flag { + name: "multilang_extra_launch" + namespace: "machine_learning" + description: "Feature flag for adding new extra for multi-lang feature" + bug: "312489931" +} diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index 4c8188801eff..a6d3bb47d9c8 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -454,7 +454,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback line.set(paint, source, 0, source.length(), Layout.DIR_LEFT_TO_RIGHT, Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null, mEllipsizedStart, mEllipsizedStart + mEllipsizedCount, useFallbackLineSpacing); - mMax = (int) Math.ceil(line.metrics(null, null, false)); + mMax = (int) Math.ceil(line.metrics(null, null, false, null)); TextLine.recycle(line); } @@ -603,7 +603,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback 0 /* ellipsisStart, 0 since text has not been ellipsized at this point */, 0 /* ellipsisEnd, 0 since text has not been ellipsized at this point */, useFallbackLineSpacing); - fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false)); + fm.width = (int) Math.ceil(line.metrics(fm, fm.mDrawingBounds, false, null)); TextLine.recycle(line); return fm; diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java index c9906cc68f3d..eca848ae1ea3 100644 --- a/core/java/android/text/Layout.java +++ b/core/java/android/text/Layout.java @@ -18,6 +18,7 @@ package android.text; import static com.android.text.flags.Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE; import static com.android.text.flags.Flags.FLAG_USE_BOUNDS_FOR_WIDTH; +import static com.android.text.flags.Flags.FLAG_INTER_CHARACTER_JUSTIFICATION; import android.annotation.FlaggedApi; import android.annotation.FloatRange; @@ -50,8 +51,10 @@ import com.android.internal.util.GrowingArrayUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.text.BreakIterator; import java.util.Arrays; import java.util.List; +import java.util.Locale; /** * A base class that manages text layout in visual elements on @@ -669,7 +672,8 @@ public abstract class Layout { int start = previousLineEnd; previousLineEnd = getLineStart(lineNum + 1); final boolean justify = isJustificationRequired(lineNum); - int end = getLineVisibleEnd(lineNum, start, previousLineEnd); + int end = getLineVisibleEnd(lineNum, start, previousLineEnd, + true /* trailingSpaceAtLastLineIsVisible */); paint.setStartHyphenEdit(getStartHyphenEdit(lineNum)); paint.setEndHyphenEdit(getEndHyphenEdit(lineNum)); @@ -1056,7 +1060,7 @@ public abstract class Layout { if (isJustificationRequired(line)) { tl.justify(getJustifyWidth(line)); } - tl.metrics(null, rectF, false); + tl.metrics(null, rectF, false, null); float lineLeft = rectF.left; float lineRight = rectF.right; @@ -1456,7 +1460,7 @@ public abstract class Layout { tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops, getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line), isFallbackLineSpacingEnabled()); - float wid = tl.measure(offset - start, trailing, null, null); + float wid = tl.measure(offset - start, trailing, null, null, null); TextLine.recycle(tl); if (clamped && wid > mWidth) { @@ -1792,12 +1796,69 @@ public abstract class Layout { if (isJustificationRequired(line)) { tl.justify(getJustifyWidth(line)); } - final float width = tl.metrics(null, null, mUseBoundsForWidth); + final float width = tl.metrics(null, null, mUseBoundsForWidth, null); TextLine.recycle(tl); return width; } /** + * Returns the number of letter spacing unit in the line. + * + * <p> + * This API returns a number of letters that is a target of letter spacing. The letter spacing + * won't be added to the middle of the characters that are needed to be treated as a single, + * e.g., ligatured or conjunct form. Note that this value is different from the number of] + * grapheme clusters that is calculated by {@link BreakIterator#getCharacterInstance(Locale)}. + * For example, if the "fi" is ligatured, the ligatured form is treated as single uni and letter + * spacing is not added, but it has two separate grapheme cluster. + * + * <p> + * This value is used for calculating the letter spacing amount for the justification because + * the letter spacing is applied between clusters. For example, if extra {@code W} pixels needed + * to be filled by letter spacing, the amount of letter spacing to be applied is + * {@code W}/(letter spacing unit count - 1) px. + * + * @param line the index of the line + * @param includeTrailingWhitespace whether to include trailing whitespace + * @return the number of cluster count in the line. + */ + @IntRange(from = 0) + @FlaggedApi(FLAG_INTER_CHARACTER_JUSTIFICATION) + public int getLineLetterSpacingUnitCount(@IntRange(from = 0) int line, + boolean includeTrailingWhitespace) { + final int start = getLineStart(line); + final int end = includeTrailingWhitespace ? getLineEnd(line) + : getLineVisibleEnd(line, getLineStart(line), getLineStart(line + 1), + false // trailingSpaceAtLastLineIsVisible: Treating trailing whitespaces at + // the last line as a invisible chars for single line justification. + ); + + final Directions directions = getLineDirections(line); + // Returned directions can actually be null + if (directions == null) { + return 0; + } + final int dir = getParagraphDirection(line); + + final TextLine tl = TextLine.obtain(); + final TextPaint paint = mWorkPaint; + paint.set(mPaint); + paint.setStartHyphenEdit(getStartHyphenEdit(line)); + paint.setEndHyphenEdit(getEndHyphenEdit(line)); + tl.set(paint, mText, start, end, dir, directions, + false, null, // tab width is not used for cluster counting. + getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line), + isFallbackLineSpacingEnabled()); + if (mLineInfo == null) { + mLineInfo = new TextLine.LineInfo(); + } + mLineInfo.setClusterCount(0); + tl.metrics(null, null, mUseBoundsForWidth, mLineInfo); + TextLine.recycle(tl); + return mLineInfo.getClusterCount(); + } + + /** * Returns the signed horizontal extent of the specified line, excluding * leading margin. If full is false, excludes trailing whitespace. * @param line the index of the line @@ -1823,7 +1884,7 @@ public abstract class Layout { if (isJustificationRequired(line)) { tl.justify(getJustifyWidth(line)); } - final float width = tl.metrics(null, null, mUseBoundsForWidth); + final float width = tl.metrics(null, null, mUseBoundsForWidth, null); TextLine.recycle(tl); return width; } @@ -2432,14 +2493,21 @@ public abstract class Layout { * is not counted) on the specified line. */ public int getLineVisibleEnd(int line) { - return getLineVisibleEnd(line, getLineStart(line), getLineStart(line+1)); + return getLineVisibleEnd(line, getLineStart(line), getLineStart(line + 1), + true /* trailingSpaceAtLastLineIsVisible */); } - private int getLineVisibleEnd(int line, int start, int end) { + private int getLineVisibleEnd(int line, int start, int end, + boolean trailingSpaceAtLastLineIsVisible) { CharSequence text = mText; char ch; - if (line == getLineCount() - 1) { - return end; + + // Historically, trailing spaces at the last line is counted as visible. However, this + // doesn't work well for justification. + if (trailingSpaceAtLastLineIsVisible) { + if (line == getLineCount() - 1) { + return end; + } } for (; end > start; end--) { @@ -2939,7 +3007,7 @@ public abstract class Layout { tl.set(paint, text, start, end, dir, directions, hasTabs, tabStops, 0 /* ellipsisStart */, 0 /* ellipsisEnd */, false /* use fallback line spacing. unused */); - return margin + Math.abs(tl.metrics(null, null, useBoundsForWidth)); + return margin + Math.abs(tl.metrics(null, null, useBoundsForWidth, null)); } finally { TextLine.recycle(tl); if (mt != null) { @@ -3337,6 +3405,8 @@ public abstract class Layout { private boolean mUseBoundsForWidth; private @Nullable Paint.FontMetrics mMinimumFontMetrics; + private TextLine.LineInfo mLineInfo = null; + /** @hide */ @IntDef(prefix = { "DIR_" }, value = { DIR_LEFT_TO_RIGHT, diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index f9abec04e71d..135935cb0632 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -76,6 +76,21 @@ public class TextLine { private RectF mTmpRectForPaintAPI; private Rect mTmpRectForPrecompute; + // Recycling object for Paint APIs. Do not use outside getRunAdvances method. + private Paint.RunInfo mRunInfo; + + public static final class LineInfo { + private int mClusterCount; + + public int getClusterCount() { + return mClusterCount; + } + + public void setClusterCount(int clusterCount) { + mClusterCount = clusterCount; + } + }; + private boolean mUseFallbackExtent = false; // The start and end of a potentially existing ellipsis on this text line. @@ -270,7 +285,7 @@ public class TextLine { // width. return; } - final float width = Math.abs(measure(end, false, null, null)); + final float width = Math.abs(measure(end, false, null, null, null)); mAddedWidthForJustify = (justifyWidth - width) / spaces; mIsJustifying = true; } @@ -315,10 +330,12 @@ public class TextLine { * @param drawBounds output parameter for drawing bounding box. optional. * @param returnDrawWidth true for returning width of the bounding box, false for returning * total advances. + * @param lineInfo an optional output parameter for filling line information. * @return the signed width of the line */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) - public float metrics(FontMetricsInt fmi, @Nullable RectF drawBounds, boolean returnDrawWidth) { + public float metrics(FontMetricsInt fmi, @Nullable RectF drawBounds, boolean returnDrawWidth, + @Nullable LineInfo lineInfo) { if (returnDrawWidth) { if (drawBounds == null) { if (mTmpRectForMeasure == null) { @@ -327,7 +344,7 @@ public class TextLine { drawBounds = mTmpRectForMeasure; } drawBounds.setEmpty(); - float w = measure(mLen, false, fmi, drawBounds); + float w = measure(mLen, false, fmi, drawBounds, lineInfo); float boundsWidth = drawBounds.width(); if (Math.abs(w) > boundsWidth) { return w; @@ -337,7 +354,7 @@ public class TextLine { return Math.signum(w) * boundsWidth; } } else { - return measure(mLen, false, fmi, drawBounds); + return measure(mLen, false, fmi, drawBounds, lineInfo); } } @@ -407,12 +424,13 @@ public class TextLine { * the edge of the preceding run's edge. See example above. * @param fmi receives metrics information about the requested character, can be null * @param drawBounds output parameter for drawing bounding box. optional. + * @param lineInfo an optional output parameter for filling line information. * @return the signed graphical offset from the leading margin to the requested character edge. * The positive value means the offset is right from the leading edge. The negative * value means the offset is left from the leading edge. */ public float measure(@IntRange(from = 0) int offset, boolean trailing, - @NonNull FontMetricsInt fmi, @Nullable RectF drawBounds) { + @NonNull FontMetricsInt fmi, @Nullable RectF drawBounds, @Nullable LineInfo lineInfo) { if (offset > mLen) { throw new IndexOutOfBoundsException( "offset(" + offset + ") should be less than line limit(" + mLen + ")"); @@ -437,16 +455,16 @@ public class TextLine { if (targetIsInThisSegment && sameDirection) { return h + measureRun(segStart, offset, j, runIsRtl, fmi, drawBounds, null, - 0, h); + 0, h, lineInfo); } final float segmentWidth = measureRun(segStart, j, j, runIsRtl, fmi, drawBounds, - null, 0, h); + null, 0, h, lineInfo); h += sameDirection ? segmentWidth : -segmentWidth; if (targetIsInThisSegment) { return h + measureRun(segStart, offset, j, runIsRtl, null, null, null, 0, - h); + h, lineInfo); } if (j != runLimit) { // charAt(j) == TAB_CHAR @@ -537,7 +555,8 @@ public class TextLine { final boolean sameDirection = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl; final float segmentWidth = - measureRun(segStart, j, j, runIsRtl, null, null, advances, segStart, 0); + measureRun(segStart, j, j, runIsRtl, null, null, advances, segStart, 0, + null); final float oldh = h; h += sameDirection ? segmentWidth : -segmentWidth; @@ -578,7 +597,7 @@ public class TextLine { } /** - * @see #measure(int, boolean, FontMetricsInt, RectF) + * @see #measure(int, boolean, FontMetricsInt, RectF, LineInfo) * @return The measure results for all possible offsets */ @VisibleForTesting @@ -610,7 +629,7 @@ public class TextLine { final float previousSegEndHorizontal = measurement[segStart]; final float width = measureRun(segStart, j, j, runIsRtl, fmi, null, measurement, segStart, - 0); + 0, null); horizontal += sameDirection ? width : -width; float currHorizontal = sameDirection ? oldHorizontal : horizontal; @@ -675,14 +694,14 @@ public class TextLine { boolean needWidth) { if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) { - float w = -measureRun(start, limit, limit, runIsRtl, null, null, null, 0, 0); + float w = -measureRun(start, limit, limit, runIsRtl, null, null, null, 0, 0, null); handleRun(start, limit, limit, runIsRtl, c, null, x + w, top, - y, bottom, null, null, false, null, 0); + y, bottom, null, null, false, null, 0, null); return w; } return handleRun(start, limit, limit, runIsRtl, c, null, x, top, - y, bottom, null, null, needWidth, null, 0); + y, bottom, null, null, needWidth, null, 0, null); } /** @@ -698,19 +717,20 @@ public class TextLine { * @param advances receives the advance information about the requested run, can be null. * @param advancesIndex the start index to fill in the advance information. * @param x horizontal offset of the run. + * @param lineInfo an optional output parameter for filling line information. * @return the signed width from the start of the run to the leading edge * of the character at offset, based on the run (not paragraph) direction */ private float measureRun(int start, int offset, int limit, boolean runIsRtl, @Nullable FontMetricsInt fmi, @Nullable RectF drawBounds, @Nullable float[] advances, - int advancesIndex, float x) { + int advancesIndex, float x, @Nullable LineInfo lineInfo) { if (drawBounds != null && (mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) { - float w = -measureRun(start, offset, limit, runIsRtl, null, null, null, 0, 0); + float w = -measureRun(start, offset, limit, runIsRtl, null, null, null, 0, 0, null); return handleRun(start, offset, limit, runIsRtl, null, null, x + w, 0, 0, 0, fmi, - drawBounds, true, advances, advancesIndex); + drawBounds, true, advances, advancesIndex, lineInfo); } return handleRun(start, offset, limit, runIsRtl, null, null, x, 0, 0, 0, fmi, drawBounds, - true, advances, advancesIndex); + true, advances, advancesIndex, lineInfo); } /** @@ -729,14 +749,14 @@ public class TextLine { int limit, boolean runIsRtl, float x, boolean needWidth) { if ((mDir == Layout.DIR_LEFT_TO_RIGHT) == runIsRtl) { - float w = -measureRun(start, limit, limit, runIsRtl, null, null, null, 0, 0); + float w = -measureRun(start, limit, limit, runIsRtl, null, null, null, 0, 0, null); handleRun(start, limit, limit, runIsRtl, null, consumer, x + w, 0, 0, 0, null, null, - false, null, 0); + false, null, 0, null); return w; } return handleRun(start, limit, limit, runIsRtl, null, consumer, x, 0, 0, 0, null, null, - needWidth, null, 0); + needWidth, null, 0, null); } @@ -1077,16 +1097,35 @@ public class TextLine { private float getRunAdvance(TextPaint wp, int start, int end, int contextStart, int contextEnd, boolean runIsRtl, int offset, @Nullable float[] advances, int advancesIndex, - RectF drawingBounds) { + RectF drawingBounds, @Nullable LineInfo lineInfo) { + if (lineInfo != null) { + if (mRunInfo == null) { + mRunInfo = new Paint.RunInfo(); + } + mRunInfo.setClusterCount(0); + } else { + mRunInfo = null; + } if (mCharsValid) { - return wp.getRunCharacterAdvance(mChars, start, end, contextStart, contextEnd, - runIsRtl, offset, advances, advancesIndex, drawingBounds); + float r = wp.getRunCharacterAdvance(mChars, start, end, contextStart, contextEnd, + runIsRtl, offset, advances, advancesIndex, drawingBounds, mRunInfo); + if (lineInfo != null) { + lineInfo.setClusterCount(lineInfo.getClusterCount() + mRunInfo.getClusterCount()); + } + return r; } else { final int delta = mStart; - if (mComputed == null || advances != null) { - return wp.getRunCharacterAdvance(mText, delta + start, delta + end, + // TODO: Add cluster information to the PrecomputedText for better performance of + // justification. + if (mComputed == null || advances != null || lineInfo != null) { + float r = wp.getRunCharacterAdvance(mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, runIsRtl, - delta + offset, advances, advancesIndex, drawingBounds); + delta + offset, advances, advancesIndex, drawingBounds, mRunInfo); + if (lineInfo != null) { + lineInfo.setClusterCount( + lineInfo.getClusterCount() + mRunInfo.getClusterCount()); + } + return r; } else { if (drawingBounds != null) { if (mTmpRectForPrecompute == null) { @@ -1120,6 +1159,7 @@ public class TextLine { * @param decorations the list of locations and paremeters for drawing decorations * @param advances receives the advance information about the requested run, can be null. * @param advancesIndex the start index to fill in the advance information. + * @param lineInfo an optional output parameter for filling line information. * @return the signed width of the run based on the run direction; only * valid if needWidth is true */ @@ -1128,7 +1168,7 @@ public class TextLine { Canvas c, TextShaper.GlyphsConsumer consumer, float x, int top, int y, int bottom, FontMetricsInt fmi, RectF drawBounds, boolean needWidth, int offset, @Nullable ArrayList<DecorationInfo> decorations, - @Nullable float[] advances, int advancesIndex) { + @Nullable float[] advances, int advancesIndex, @Nullable LineInfo lineInfo) { if (mIsJustifying) { wp.setWordSpacing(mAddedWidthForJustify); @@ -1155,7 +1195,8 @@ public class TextLine { mTmpRectForPaintAPI = new RectF(); } totalWidth = getRunAdvance(wp, start, end, contextStart, contextEnd, runIsRtl, offset, - advances, advancesIndex, drawBounds == null ? null : mTmpRectForPaintAPI); + advances, advancesIndex, drawBounds == null ? null : mTmpRectForPaintAPI, + lineInfo); if (drawBounds != null) { if (runIsRtl) { mTmpRectForPaintAPI.offset(x - totalWidth, 0); @@ -1206,9 +1247,9 @@ public class TextLine { final int decorationStart = Math.max(info.start, start); final int decorationEnd = Math.min(info.end, offset); float decorationStartAdvance = getRunAdvance(wp, start, end, contextStart, - contextEnd, runIsRtl, decorationStart, null, 0, null); + contextEnd, runIsRtl, decorationStart, null, 0, null, null); float decorationEndAdvance = getRunAdvance(wp, start, end, contextStart, - contextEnd, runIsRtl, decorationEnd, null, 0, null); + contextEnd, runIsRtl, decorationEnd, null, 0, null, null); final float decorationXLeft, decorationXRight; if (runIsRtl) { decorationXLeft = rightX - decorationEndAdvance; @@ -1377,6 +1418,7 @@ public class TextLine { * @param needWidth true if the width is required * @param advances receives the advance information about the requested run, can be null. * @param advancesIndex the start index to fill in the advance information. + * @param lineInfo an optional output parameter for filling line information. * @return the signed width of the run based on the run direction; only * valid if needWidth is true */ @@ -1384,7 +1426,7 @@ public class TextLine { int limit, boolean runIsRtl, Canvas c, TextShaper.GlyphsConsumer consumer, float x, int top, int y, int bottom, FontMetricsInt fmi, RectF drawBounds, boolean needWidth, - @Nullable float[] advances, int advancesIndex) { + @Nullable float[] advances, int advancesIndex, @Nullable LineInfo lineInfo) { if (measureLimit < start || measureLimit > limit) { throw new IndexOutOfBoundsException("measureLimit (" + measureLimit + ") is out of " @@ -1431,7 +1473,7 @@ public class TextLine { wp.setEndHyphenEdit(adjustEndHyphenEdit(limit, wp.getEndHyphenEdit())); return handleText(wp, start, limit, start, limit, runIsRtl, c, consumer, x, top, y, bottom, fmi, drawBounds, needWidth, measureLimit, null, advances, - advancesIndex); + advancesIndex, lineInfo); } // Shaping needs to take into account context up to metric boundaries, @@ -1523,7 +1565,7 @@ public class TextLine { consumer, x, top, y, bottom, fmi, drawBounds, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations, - advances, advancesIndex + activeStart - start); + advances, advancesIndex + activeStart - start, lineInfo); activeStart = j; activePaint.set(wp); @@ -1551,7 +1593,7 @@ public class TextLine { x += handleText(activePaint, activeStart, activeEnd, i, inext, runIsRtl, c, consumer, x, top, y, bottom, fmi, drawBounds, needWidth || activeEnd < measureLimit, Math.min(activeEnd, mlimit), mDecorations, - advances, advancesIndex + activeStart - start); + advances, advancesIndex + activeStart - start, lineInfo); } return x - originalX; diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index a74cbe46b404..f0e673b3e3ac 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -378,6 +378,13 @@ public final class Choreographer { } /** + * @hide + */ + public Looper getLooper() { + return mLooper; + } + + /** * The amount of time, in milliseconds, between each frame of the animation. * <p> * This is a requested time that the animation will attempt to honor, but the actual delay diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 9bf43a390d70..1d81be17f580 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -370,4 +370,14 @@ interface IWindowSession { boolean transferEmbeddedTouchFocusToHost(IWindow embeddedWindow); boolean transferHostTouchGestureToEmbedded(IWindow hostWindow, IBinder transferTouchToken); + + /** + * Moves the focus to the adjacent window if there is one in the given direction. This can only + * move the focus to the window in the same leaf task. + * + * @param fromWindow The calling window that the focus is moved from. + * @param direction The {@link android.view.View.FocusDirection} that the new focus should go. + * @return {@code true} if the focus changes. Otherwise, {@code false}. + */ + boolean moveFocusToAdjacentWindow(IWindow fromWindow, int direction); } diff --git a/core/java/android/view/SurfaceControlInputReceiver.java b/core/java/android/view/SurfaceControlInputReceiver.java new file mode 100644 index 000000000000..81e444859b76 --- /dev/null +++ b/core/java/android/view/SurfaceControlInputReceiver.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; + +import com.android.window.flags.Flags; + +/** + * Provides a mechanism for a SurfaceControl to receive input events. + */ +@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) +public interface SurfaceControlInputReceiver { + /** + * When input events are batched, this is called at most once per frame. When non batched, this + * is called immediately for the input event. + * + * @param event The input event that was received. This input event object will become invalid + * and recycled after this method is invoked. If there is need to persist this + * object beyond the scope of this method, the overriding code should make a copy + * of this object. For example, using + * {@link MotionEvent#obtain(MotionEvent other)} or + * {@link KeyEvent#KeyEvent(KeyEvent)} } + * @return true if the event was handled, false otherwise. + */ + boolean onInputEvent(@NonNull InputEvent event); + +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 2b99e1e9f79b..257ecc565c87 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -33170,6 +33170,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public void setFrameContentVelocity(float pixelsPerSecond) { if (viewVelocityApi()) { mFrameContentVelocity = Math.abs(pixelsPerSecond); + + if (sToolkitMetricsForFrameRateDecisionFlagValue) { + Trace.setCounter("Set frame velocity", (long) mFrameContentVelocity); + } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 350876c828b7..c66f3c8032fd 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -16,6 +16,7 @@ package android.view; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.content.pm.ActivityInfo.OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS; import static android.graphics.HardwareRenderer.SYNC_CONTEXT_IS_STOPPED; import static android.graphics.HardwareRenderer.SYNC_LOST_SURFACE_REWARD_IF_FOUND; @@ -7236,7 +7237,7 @@ public final class ViewRootImpl implements ViewParent, } private boolean performFocusNavigation(KeyEvent event) { - int direction = 0; + @FocusDirection int direction = 0; switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: if (event.hasNoModifiers()) { @@ -7288,6 +7289,8 @@ public final class ViewRootImpl implements ViewParent, isFastScrolling)); return true; } + } else if (moveFocusToAdjacentWindow(direction)) { + return true; } // Give the focused view a last chance to handle the dpad key. @@ -7297,12 +7300,26 @@ public final class ViewRootImpl implements ViewParent, } else { if (mView.restoreDefaultFocus()) { return true; + } else if (moveFocusToAdjacentWindow(direction)) { + return true; } } } return false; } + private boolean moveFocusToAdjacentWindow(@FocusDirection int direction) { + if (getConfiguration().windowConfiguration.getWindowingMode() + != WINDOWING_MODE_MULTI_WINDOW) { + return false; + } + try { + return mWindowSession.moveFocusToAdjacentWindow(mWindow, direction); + } catch (RemoteException e) { + return false; + } + } + private boolean performKeyboardGroupNavigation(int direction) { final View focused = mView.findFocus(); if (focused == null && mView.restoreDefaultFocus()) { diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index d8fa41589f29..42355bb17c2d 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -109,6 +109,7 @@ import android.graphics.Region; import android.os.Build; import android.os.Bundle; import android.os.IBinder; +import android.os.Looper; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemProperties; @@ -1358,9 +1359,8 @@ public interface WindowManager extends ViewManager { * android:value="false"/> * </application> * </pre> - * @hide */ - // TODO(b/294227289): Make this public API + @FlaggedApi(Flags.FLAG_APP_COMPAT_PROPERTIES_API) String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE"; @@ -1402,9 +1402,8 @@ public interface WindowManager extends ViewManager { * android:value="false"/> * </application> * </pre> - * @hide */ - // TODO(b/294227289): Make this public API + @FlaggedApi(Flags.FLAG_APP_COMPAT_PROPERTIES_API) String PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"; @@ -6015,4 +6014,94 @@ public interface WindowManager extends ViewManager { default void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { throw new UnsupportedOperationException(); } + + /** + * Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will + * receive batched input event. For those events that are batched, the invocation will happen + * once per {@link Choreographer} frame, and other input events will be delivered immediately. + * This is different from + * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper, + * SurfaceControlInputReceiver)} in that the input events are received batched. The caller must + * invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources when + * no longer needing to use the {@link SurfaceControlInputReceiver} + * + * @param displayId The display that the SurfaceControl will be placed on. Input will + * only work + * if SurfaceControl is on that display and that display was touched. + * @param surfaceControl The SurfaceControl to register the InputChannel for + * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs + * to ensure the host receives the ANR if any issues with touch on the + * InputChannel + * @param choreographer The Choreographer used for batching. This should match the rendering + * Choreographer. + * @param receiver The SurfaceControlInputReceiver that will receive the input events + * @return an {@link IBinder} token that is used to unregister the input receiver via + * {@link #unregisterSurfaceControlInputReceiver(IBinder)}. + * @see #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper, + * SurfaceControlInputReceiver) + */ + @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) + @NonNull + default IBinder registerBatchedSurfaceControlInputReceiver(int displayId, + @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) { + throw new UnsupportedOperationException( + "registerBatchedSurfaceControlInputReceiver is not implemented"); + } + + /** + * Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will + * receive every input event. This is different than calling @link + * #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer, + * SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller + * must invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources + * when no longer needing to use the {@link SurfaceControlInputReceiver} + * + * @param displayId The display that the SurfaceControl will be placed on. Input will only + * work if SurfaceControl is on that display and that display was + * touched. + * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs + * to ensure the host receives the ANR if any issues with touch on the + * InputChannel + * @param surfaceControl The SurfaceControl to register the InputChannel for + * @param looper The looper to use when invoking callbacks. + * @param receiver The SurfaceControlInputReceiver that will receive the input events + * @return an {@link IBinder} token that is used to unregister the input receiver via + * {@link #unregisterSurfaceControlInputReceiver(IBinder)}. + * @see #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer, + * SurfaceControlInputReceiver) + **/ + @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) + @NonNull + default IBinder registerUnbatchedSurfaceControlInputReceiver(int displayId, + @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) { + throw new UnsupportedOperationException( + "registerUnbatchedSurfaceControlInputReceiver is not implemented"); + } + + /** + * Unregisters and cleans up the registered {@link SurfaceControlInputReceiver} for the + * specified token. + * <p> + * Must be called on the same {@link Looper} thread to which was passed to the + * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, + * Choreographer, + * SurfaceControlInputReceiver)} or + * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper, + * SurfaceControlInputReceiver)} + * + * @param token The token that was returned via + * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder, + * SurfaceControl, + * Choreographer, SurfaceControlInputReceiver)} or + * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, + * SurfaceControl, + * Looper, SurfaceControlInputReceiver)} + */ + @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER) + default void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) { + throw new UnsupportedOperationException( + "unregisterSurfaceControlInputReceiver is not implemented"); + } } diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index f1e406196abf..8d40f9a4f7b1 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; + import android.animation.ValueAnimator; import android.annotation.NonNull; import android.annotation.Nullable; @@ -24,8 +26,10 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; import android.graphics.HardwareRenderer; +import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -46,6 +50,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.IntConsumer; @@ -151,6 +156,9 @@ public final class WindowManagerGlobal { private final TrustedPresentationListener mTrustedPresentationListener = new TrustedPresentationListener(); + private final ConcurrentHashMap<IBinder, InputEventReceiver> mSurfaceControlInputReceivers = + new ConcurrentHashMap<>(); + private WindowManagerGlobal() { } @@ -808,6 +816,74 @@ public final class WindowManagerGlobal { mTrustedPresentationListener.removeListener(listener); } + IBinder registerBatchedSurfaceControlInputReceiver(int displayId, + @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) { + IBinder clientToken = new Binder(); + InputChannel inputChannel = new InputChannel(); + try { + WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl, + clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null, + surfaceControl.getName(), inputChannel); + } catch (RemoteException e) { + Log.e(TAG, "Failed to create input channel", e); + e.rethrowAsRuntimeException(); + } + + mSurfaceControlInputReceivers.put(clientToken, + new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(), + choreographer) { + @Override + public void onInputEvent(InputEvent event) { + boolean handled = receiver.onInputEvent(event); + finishInputEvent(event, handled); + } + }); + return clientToken; + } + + IBinder registerUnbatchedSurfaceControlInputReceiver( + int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) { + IBinder clientToken = new Binder(); + InputChannel inputChannel = new InputChannel(); + try { + WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl, + clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null, + surfaceControl.getName(), inputChannel); + } catch (RemoteException e) { + Log.e(TAG, "Failed to create input channel", e); + e.rethrowAsRuntimeException(); + } + + mSurfaceControlInputReceivers.put(clientToken, + new InputEventReceiver(inputChannel, looper) { + @Override + public void onInputEvent(InputEvent event) { + boolean handled = receiver.onInputEvent(event); + finishInputEvent(event, handled); + } + }); + + return clientToken; + } + + void unregisterSurfaceControlInputReceiver(IBinder token) { + InputEventReceiver inputEventReceiver = mSurfaceControlInputReceivers.get(token); + if (inputEventReceiver == null) { + Log.w(TAG, "No registered input event receiver with token: " + token); + return; + } + try { + WindowManagerGlobal.getWindowSession().remove(token); + } catch (RemoteException e) { + Log.e(TAG, "Failed to remove input channel", e); + e.rethrowAsRuntimeException(); + } + + inputEventReceiver.dispose(); + } + private final class TrustedPresentationListener extends ITrustedPresentationListener.Stub { private static int sId = 0; diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index b4b1fde89a46..aaf5fcc6f095 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -32,6 +32,7 @@ import android.graphics.Bitmap; import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.os.StrictMode; import android.util.Log; @@ -520,6 +521,28 @@ public final class WindowManagerImpl implements WindowManager { @Override public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) { mGlobal.unregisterTrustedPresentationListener(listener); + } + + @NonNull + @Override + public IBinder registerBatchedSurfaceControlInputReceiver(int displayId, + @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) { + return mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken, + surfaceControl, choreographer, receiver); + } + @NonNull + @Override + public IBinder registerUnbatchedSurfaceControlInputReceiver( + int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl, + @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) { + return mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken, + surfaceControl, looper, receiver); + } + + @Override + public void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) { + mGlobal.unregisterSurfaceControlInputReceiver(token); } } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index d6ac56239aed..b95e4595d6b9 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -30,6 +30,7 @@ import android.os.RemoteCallback; import android.os.RemoteException; import android.util.Log; import android.util.MergedConfiguration; +import android.view.View.FocusDirection; import android.view.WindowInsets.Type.InsetsType; import android.window.ClientWindowFrames; import android.window.OnBackInvokedCallbackInfo; @@ -665,6 +666,13 @@ public class WindowlessWindowManager implements IWindowSession { return false; } + @Override + public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { + Log.e(TAG, "Received request to moveFocusToAdjacentWindow on" + + " WindowlessWindowManager. We shouldn't get here!"); + return false; + } + void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) { IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder(); IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder(); diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 48f8f1bbe367..c7355c144c5f 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -99,3 +99,10 @@ flag { description: "Feature flag for system pinch zoom gesture detector and related opt-out apis" bug: "283323770" } + +flag { + name: "support_system_pinch_zoom_opt_out_apis" + namespace: "accessibility" + description: "Feature flag for declaring system pinch zoom opt-out apis" + bug: "315089687" +} diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 70d8abe1dc27..57a3b765641d 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -109,6 +109,40 @@ public class AnimationUtils { } /** + * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current + * thread. This is used by {@link android.view.Choreographer} to ensure that all accesses + * during a vsync update are synchronized to the timestamp of the vsync. + * + * It is also exposed to tests to allow for rapid, flake-free headless testing. + * + * Must be followed by a call to {@link #unlockAnimationClock()} to allow time to + * progress. Failing to do this will result in stuck animations, scrolls, and flings. + * + * Note that time is not allowed to "rewind" and must perpetually flow forward. So the + * lock may fail if the time is in the past from a previously returned value, however + * time will be frozen for the duration of the lock. The clock is a thread-local, so + * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and + * {@link #currentAnimationTimeMillis()} are all called on the same thread. + * + * This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()} + * will unlock the clock for everyone on the same thread. It is therefore recommended + * for tests to use their own thread to ensure that there is no collision with any existing + * {@link android.view.Choreographer} instance. + * + * Have to add the method back because of b/307888459. + * Remove this method once the lockAnimationClock(long, long) change + * is landed to aosp/android14-tests-dev branch. + * + * @hide + */ + @TestApi + public static void lockAnimationClock(long vsyncMillis) { + AnimationState state = sAnimationState.get(); + state.animationClockLocked = true; + state.currentVsyncTimeMillis = vsyncMillis; + } + + /** * Frees the time lock set in place by {@link #lockAnimationClock(long)}. Must be called * to allow the animation clock to self-update. * diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig index a74b06a491e8..9f9b7b4b68a9 100644 --- a/core/java/android/view/flags/view_flags.aconfig +++ b/core/java/android/view/flags/view_flags.aconfig @@ -1,6 +1,13 @@ package: "android.view.flags" flag { + name: "enable_surface_native_alloc_registration" + namespace: "toolkit" + description: "Feature flag for registering surfaces with the VM for faster cleanup" + bug: "306193257" +} + +flag { name: "enable_use_measure_cache_during_force_layout" namespace: "toolkit" description: "Enables using the measure cache during a view force layout from the second " diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index bb7677d6a571..ccc5dbb2f580 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -47,3 +47,10 @@ flag { is_fixed_read_only: true } +flag { + name: "use_zero_jank_proxy" + namespace: "input_method" + description: "Feature flag for using a proxy that uses async calls to achieve zero jank for IMMS calls." + bug: "293640003" + is_fixed_read_only: true +} diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index ef5004536354..1d2f65353a65 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -16,6 +16,9 @@ package android.view.textclassifier; +import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS; + +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -108,6 +111,9 @@ public interface TextClassifier { String TYPE_DATE_TIME = "datetime"; /** Flight number in IATA format. */ String TYPE_FLIGHT_NUMBER = "flight"; + /** One-time login codes */ + @FlaggedApi(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS) + String TYPE_OTP_CODE = "otp_code"; /** * Word that users may be interested to look up for meaning. * @hide @@ -126,7 +132,8 @@ public interface TextClassifier { TYPE_DATE, TYPE_DATE_TIME, TYPE_FLIGHT_NUMBER, - TYPE_DICTIONARY + TYPE_DICTIONARY, + TYPE_OTP_CODE }) @interface EntityType {} diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java index bdaad2b68fc2..473b814fc4a7 100644 --- a/core/java/android/window/SplashScreenView.java +++ b/core/java/android/window/SplashScreenView.java @@ -47,6 +47,7 @@ import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; import android.view.Window; +import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; @@ -337,7 +338,14 @@ public final class SplashScreenView extends FrameLayout { "SplashScreenView"); ImageView imageView = new ImageView(viewContext); imageView.setBackground(mIconDrawable); - viewHost.setView(imageView, mIconSize, mIconSize); + final int windowFlag = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + final WindowManager.LayoutParams lp = + new WindowManager.LayoutParams(mIconSize, mIconSize, + WindowManager.LayoutParams.TYPE_APPLICATION, windowFlag, + PixelFormat.TRANSPARENT); + viewHost.setView(imageView, lp); SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage(); surfaceView.setChildSurfacePackage(surfacePackage); view.mSurfacePackage = surfacePackage; diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 3794c5d647a4..3c3c8469b3a4 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -72,3 +72,11 @@ flag { is_fixed_read_only: true bug: "295038072" } + +flag { + namespace: "window_surfaces" + name: "surface_control_input_receiver" + description: "Enable public API to register an InputReceiver for a SurfaceControl" + is_fixed_read_only: true + bug: "278757236" +} diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index f2bce9c44001..bb16ad2cb8de 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -72,7 +72,7 @@ flag { name: "predictive_back_system_animations" namespace: "systemui" description: "Predictive back for system animations" - bug: "309545085" + bug: "319421778" is_fixed_read_only: true } diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index 4fe9aea91358..85bdbb908205 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -80,5 +80,11 @@ interface IAppWidgetService { in Bundle extras, in IntentSender resultIntent); boolean isRequestPinAppWidgetSupported(); oneway void noteAppWidgetTapped(in String callingPackage, in int appWidgetId); + void setWidgetPreview(in ComponentName providerComponent, in int widgetCategories, + in RemoteViews preview); + @nullable RemoteViews getWidgetPreview(in String callingPackage, + in ComponentName providerComponent, in int profileId, in int widgetCategory); + void removeWidgetPreview(in ComponentName providerComponent, in int widgetCategories); + } diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java index e55c64199f45..fab8984ce067 100644 --- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java +++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java @@ -33,13 +33,14 @@ public class RefreshRateSettingsUtils { /** * Find the highest refresh rate among all the modes of the default display. * + * This method will acquire DisplayManager.mLock, so calling it while holding other locks + * should be done with care. * @param context The context * @return The highest refresh rate */ public static float findHighestRefreshRateForDefaultDisplay(Context context) { final DisplayManager dm = context.getSystemService(DisplayManager.class); final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY); - if (display == null) { Log.w(TAG, "No valid default display device"); return DEFAULT_REFRESH_RATE; diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java index 5d82d0469d56..12aff1c6669f 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java @@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.multiuser.Flags; import android.os.Build; import android.os.PatternMatcher; import android.util.Slog; @@ -126,6 +127,10 @@ public class ParsedProviderUtils { .setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestProvider_singleUser, sa)); + if (Flags.enableSystemUserOnlyForServicesAndProviders()) { + provider.setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SYSTEM_USER_ONLY, + R.styleable.AndroidManifestProvider_systemUserOnly, sa)); + } visibleToEphemeral = sa.getBoolean( R.styleable.AndroidManifestProvider_visibleToInstantApps, false); if (visibleToEphemeral) { diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java index a1dd19a3bc90..4ac542f84226 100644 --- a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java +++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java @@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.multiuser.Flags; import android.os.Build; import com.android.internal.R; @@ -105,6 +106,11 @@ public class ParsedServiceUtils { | flag(ServiceInfo.FLAG_SINGLE_USER, R.styleable.AndroidManifestService_singleUser, sa))); + if (Flags.enableSystemUserOnlyForServicesAndProviders()) { + service.setFlags(service.getFlags() | flag(ServiceInfo.FLAG_SYSTEM_USER_ONLY, + R.styleable.AndroidManifestService_systemUserOnly, sa)); + } + visibleToEphemeral = sa.getBoolean( R.styleable.AndroidManifestService_visibleToInstantApps, false); if (visibleToEphemeral) { diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index b6517117ca62..a5b2f65eafc7 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -96,8 +96,11 @@ static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass) static jint android_os_VintfObject_verifyBuildAtBoot(JNIEnv* env, jclass) { std::string error; + // Use temporary VintfObject, not the shared instance, to release memory + // after check. int32_t status = - VintfObject::GetInstance() + VintfObject::Builder() + .build() ->checkCompatibility(&error, ENABLE_ALL_CHECKS.disableAvb().disableKernel()); if (status) LOG(WARNING) << "VintfObject.verifyBuildAtBoot() returns " << status << ": " << error; diff --git a/core/proto/OWNERS b/core/proto/OWNERS index db391f7a8c35..a854e3626e78 100644 --- a/core/proto/OWNERS +++ b/core/proto/OWNERS @@ -18,6 +18,7 @@ per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/a per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS per-file android/hardware/sensorprivacy.proto = ntmyren@google.com,evanseverson@google.com per-file background_install_control.proto = wenhaowang@google.com,georgechan@google.com,billylau@google.com +per-file android/content/intent.proto = file:/PACKAGE_MANAGER_OWNERS # Biometrics jaggies@google.com @@ -31,5 +32,3 @@ jreck@google.com # Accessibility pweaver@google.com -hongmingjin@google.com -cbrower@google.com diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 52e0124cc681..b63021d52f1c 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -397,6 +397,8 @@ message ActivityRecordProto { optional bool should_override_min_aspect_ratio = 42; optional bool should_ignore_orientation_request_loop = 43; optional bool should_override_force_resize_app = 44; + optional bool should_enable_user_aspect_ratio_settings = 45; + optional bool is_user_fullscreen_override_enabled = 46; } /* represents WindowToken */ diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ef6caefd3daf..5f3f6419418a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5214,6 +5214,14 @@ <permission android:name="android.permission.BIND_REMOTE_DISPLAY" android:protectionLevel="signature" /> + <!-- Must be required by a android.media.tv.ad.TvAdService to ensure that only the system can + bind to it. + <p>Protection level: signature|privileged + @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") + --> + <permission android:name="android.permission.BIND_TV_AD_SERVICE" + android:protectionLevel="signature|privileged" /> + <!-- Must be required by a {@link android.media.tv.TvInputService} to ensure that only the system can bind to it. <p>Protection level: signature|privileged diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 82814626b88a..b60bd6348c00 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Laat die app toe om die voorgronddienstipe “stelselvrystelling” te gebruik"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"gebruik voorgronddienstipe “lêerbestuur”"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Laat die app toe om die voorgronddienstipe “lêerbestuur” te gebruik"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"gebruik voorgronddienstipe “spesiale gebruik”"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Laat die app toe om die voorgronddienstipe “spesiale gebruik” te gebruik"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"meet programberging-ruimte"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gebruik skermslot"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Voer jou skermslot in om voort te gaan"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Druk ferm op die sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Kan nie vingerafdruk herken nie. Probeer weer."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Maak vingerafdruksensor skoon en probeer weer"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Maak sensor skoon en probeer weer"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Druk ferm op sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kan nie jou gesig sien nie. Hou jou foon op oogvlak."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te veel beweging. Hou foon stil."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Skryf jou gesig asseblief weer in."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Kan nie gesig herken nie. Probeer weer."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Verander die posisie van jou kop effens"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kyk meer reguit na jou foon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kyk meer reguit na jou foon"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index ff7dee8c4e2f..5a6ef3c7f7dd 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"መተግበሪያው የፊት አገልግሎትን በ«systemExempted» ዓይነት እንዲጠቀም ይፈቅዳል"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"የፊት አገልግሎትን በ«fileManagement» ዓይነት ማስሄድ"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"መተግበሪያው የፊት አገልግሎቶችን በ«fileManagement» ዓይነት እንዲጠቀም ያስችላል"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"የፊት አገልግሎትን በ«specialUse» ዓይነት ማስሄድ"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"መተግበሪያው የፊት አገልግሎትን በ«specialUse» ዓይነት እንዲጠቀም ይፈቅዳል"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"የመተግበሪያ ማከማቻ ቦታ ለካ"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"የማያ ገፅ መቆለፊን ይጠቀሙ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ለመቀጠል የማያ ገፅ ቁልፍዎን ያስገቡ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ዳሳሹን በደንብ ይጫኑት"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"የጣት አሻራን መለየት አልተቻለም። እንደገና ይሞክሩ።"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"የጣት አሻራ ዳሳሽን ያጽዱ እና እንደገና ይሞክሩ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ዳሳሹን ያጽዱ እና እንደገና ይሞክሩ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ዳሳሹን ጠበቅ አድርገው ይጫኑት"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"የእርስዎን መልክ ማየት አይችልም። ስልክዎን በዓይን ትክክል ይያዙ።"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ከልክ በላይ ብዙ እንቅስቃሴ። ስልኩን ቀጥ አድርገው ይያዙት።"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"እባክዎ ፊትዎን እንደገና ያስመዝግቡ"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"መልክን መለየት አልተቻለም። እንደገና ይሞክሩ።"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"የጭንቅላትዎን ቦታ በትንሹ ይለዋውጡ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ስልክዎን ይበልጥ በቀጥታ ይመልከቱ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ስልክዎን ይበልጥ በቀጥታ ይመልከቱ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 0cc49a57dd1f..136ad53359da 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -438,6 +438,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"systemExempted\"."</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"specialUse\"."</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"قياس مساحة تخزين التطبيق"</string> @@ -636,7 +640,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"استخدام قفل الشاشة"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"أدخِل قفل الشاشة للمتابعة"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"اضغط بقوة على أداة الاستشعار"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"يتعذّر التعرّف على بصمة الإصبع. يُرجى إعادة المحاولة."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"يُرجى تنظيف مستشعر بصمات الإصبع ثم إعادة المحاولة."</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"تنظيف المستشعر ثم إعادة المحاولة"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"اضغط بقوة على أداة الاستشعار"</string> @@ -700,7 +705,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ارفع هاتفك إلى مستوى العينَين لأنّه تتعذّر رؤية وجهك"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"حركة أكثر من اللازم. يُرجى حمل الهاتف بثبات."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"يُرجى إعادة تسجيل وجهك."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"يتعذّر التعرّف على الوجه. يُرجى إعادة المحاولة."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"غيِّر موضع رأسك قليلاً."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"يُرجى النظر إلى هاتفك مباشرةً"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"يُرجى النظر إلى هاتفك مباشرةً"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index ddc236773205..fa9e2d782ef8 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"এপ্টোক \"systemExempted\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"এপ্টোক \"fileManagement\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"এপ্টোক \"specialUse\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"এপৰ ষ্ট’ৰেজৰ খালী ঠাই হিচাপ কৰক"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"স্ক্ৰীন ল\'ক ব্যৱহাৰ কৰক"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"অব্যাহত ৰাখিবলৈ আপোনাৰ স্ক্ৰীন লক দিয়ক"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ছেন্সৰটোত ভালকৈ টিপক"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ফিংগাৰপ্ৰিণ্ট চিনাক্ত কৰিব পৰা নাই। পুনৰ চেষ্টা কৰক।"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো মচি পুনৰ চেষ্টা কৰক"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ছেন্সৰটো মচি পুনৰ চেষ্টা কৰক"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ছেন্সৰটোত ভালকৈ টিপক"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"আপোনাৰ মুখাৱয়ব দেখা নাই। আপোনাৰ ফ’নটো চকুৰ স্তৰত ধৰি ৰাখক।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"বেছি লৰচৰ কৰি আছে। ফ’নটো স্থিৰকৈ ধৰক।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ন কৰক।"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"মুখাৱয়ব চিনিব নোৱাৰি। পুনৰ চেষ্টা কৰক।"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"আপোনাৰ মূৰটোৰ স্থান সামান্য সলনি কৰক"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"আপোনাৰ ফ’নটোলৈ আৰু পোনপটীয়াকৈ চাওক"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"আপোনাৰ ফ’নটোলৈ আৰু পোনপটীয়াকৈ চাওক"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 794e26a23c57..d4df38e96928 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tətbiqə \"systemExempted\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" növü olan ön fon xidmətlərini işə salmaq"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Tətbiqə \"fileManagement\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" növü olan ön fon xidmətləri işlətmək"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tətbiqə \"specialUse\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"tətbiq saxlama yaddaşını ölçmək"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran kilidindən istifadə edin"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Davam etmək üçün ekran kilidinizi daxil edin"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Sensora basıb saxlayın"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Barmaq izini tanımaq olmur. Yenidən cəhd edin."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Barmaq izi sensorunu silib yenidən cəhd edin"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Sensoru silib yenidən cəhd edin"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Sensora basıb saxlayın"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Üzünüz görünmür. Telefonunuzu göz səviyyəsində saxlayın."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Cihaz stabil deyil. Telefonu tərpətməyin."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Üzünüzü yenidən qeydiyyatdan keçirin."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Üzü tanımaq olmur. Yenə cəhd edin."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Başınızın yerini bir az dəyişdirin"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonunuza düz baxın"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonunuza düz baxın"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 8df8b8723759..e19a0b2886a0 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"pokretanje usluge u prvom planu koja pripada tipu „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokretanje usluge u prvom planu koja pripada tipu „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"merenje memorijskog prostora u aplikaciji"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristite zaključavanje ekrana"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Upotrebite zaključavanje ekrana da biste nastavili"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Čvrsto pritisnite senzor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Prepoznavanje otiska prsta nije uspelo. Probajte ponovo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Obrišite senzor za otisak prsta i probajte ponovo"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Obrišite senzor i probajte ponovo"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ne vidi se lice. Držite telefon u visini očiju."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Mnogo se pomerate. Držite telefon mirno."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrujte lice."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Lice nije prepoznato. Probajte ponovo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo pomerite glavu"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte pravo u telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte pravo u telefon"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 13801d0f3ed5..515a6a3bf4c3 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"запуск актыўнага сэрвісу тыпу \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Праграма зможа выкарыстоўваць актыўныя сэрвісы тыпу \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запуск актыўнага сэрвісу тыпу \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"вымерыць прастору для захоўвання прыкладання"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ужываць блакіроўку экрана"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Каб працягнуць, скарыстайце свой сродак блакіроўкі экрана"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Шчыльна прыкладзіце палец да сканера"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не ўдалося распазнаць адбітак пальца. Паўтарыце спробу."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Ачысціце сканер адбіткаў пальцаў і паўтарыце спробу"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Ачысціце сканер і паўтарыце спробу"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Шчыльна прыкладзіце палец да сканера"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не відаць твару. Трымайце тэлефон на ўзроўні вачэй."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Трымайце прыладу нерухома. Трымайце тэлефон роўна."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Паўтарыце рэгістрацыю твару."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Твар не распазнаны. Паўтарыце спробу."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Крыху змяніце паставу галавы"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Глядзіце прама на экран тэлефона"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Глядзіце прама на экран тэлефона"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index e0e9b09e040f..4689e32faa3c 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Разрешава на приложението да се възползва от услуги на преден план от тип systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Изпълнение на услуги на преден план от тип fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Разрешава на приложението да се възползва от услуги на преден план от тип fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"изпълнение на услуги на преден план от тип specialUse"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Разрешава на приложението да се възползва от услуги на преден план от тип specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"измерване на ползваното от приложението място в хранилището"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ползване на заключв. на екрана"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Въведете опцията си за заключване на екрана, за да продължите"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Натиснете добре върху сензора"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Отпечатъкът не може да бъде разпознат. Опитайте отново."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Почистете сензора за отпечатъци и опитайте отново"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Почистете сензора и опитайте отново"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Натиснете добре върху сензора"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Лицето не се вижда. Задръжте на нивото на очите."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Твърде много движение. Дръжте телефона неподвижно."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Моля, регистрирайте лицето си отново."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Лицето не е разпознато. Опитайте отново."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Леко променете позицията на главата си"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледайте директно към телефона си"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледайте директно към телефона си"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index cf8c64d251f7..d615cbeb0fd6 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"অ্যাপকে \"systemExempted\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করা"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"অ্যাপকে \"fileManagement\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"অ্যাপকে \"specialUse\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"অ্যাপ্লিকেশন সঞ্চয়স্থানের জায়গা পরিমাপ করে"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"স্ক্রিন লক ব্যবহার করুন"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"চালিয়ে যেতে আপনার স্ক্রিন লক ব্যবহার করুন"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"সেন্সরে জোরে প্রেস করুন"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ফিঙ্গারপ্রিন্ট শনাক্ত করা যায়নি। আবার চেষ্টা করুন।"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"আঙ্গুলের ছাপের সেন্সর পরিষ্কার করে আবার চেষ্টা করুন"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"সেন্সর পরিষ্কার করে আবার চেষ্টা করুন"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"সেন্সরে জোরে প্রেস করুন"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"আপনার মুখ দেখা যাচ্ছে না। ফোন আপনার চোখের সোজাসুজি ধরুন।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"খুব বেশি নড়ছে। ফোনটি যাতে না কাঁপে সেইভাবে ধরুন।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"আপনার মুখের ছবি আবার নথিভুক্ত করুন।"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"মুখ শনাক্ত করা যাচ্ছে না। আবার চেষ্টা করুন।"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"আপনার মাথার পজিশন সামান্য পরিবর্তন করুন"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"আপনার ফোনের দিকে একদম সোজাসুজি তাকান"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"আপনার ফোনের দিকে একদম সোজাসুজি তাকান"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index ef941e19ff37..f110a24e0c3f 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"pokreni uslugu u prvom planu s vrstom \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokreni uslugu u prvom planu s vrstom \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mjerenje prostora kojeg aplikacije zauzimaju u pohrani"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Koristi zaključavanje ekrana"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Unesite zaključavanje ekrana da nastavite"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Čvrsto pritisnite senzor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Otisak prsta nije prepoznat. Pokušajte ponovo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite senzor za otisak prsta i pokušajte ponovo"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite senzor i pokušajte ponovo"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Lice se ne vidi. Držite telefon u visini očiju."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše pokreta. Držite telefon mirno."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte lice."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Nije moguće prepoznati lice. Pokušajte ponovo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo pomjerite glavu"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte direktno u telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte direktno u telefon"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index ec14677965a7..d9744dd5b96b 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"executa serveis en primer pla amb el tipus \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executa serveis en primer pla amb el tipus \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mesura l\'espai d\'emmagatzematge d\'aplicacions"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utilitza el bloqueig de pantalla"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introdueix el teu bloqueig de pantalla per continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Prem el sensor de manera ferma"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"No es pot reconèixer l\'empremta digital. Torna-ho a provar."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Neteja el sensor d\'empremtes digitals i torna-ho a provar"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Neteja el sensor i torna-ho a provar"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Prem el sensor de manera ferma"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se\'t veu la cara. Mantén el telèfon a l\'altura dels ulls."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Massa moviment. Subjecta bé el telèfon."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Torna a registrar la teva cara."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"No podem reconèixer la cara. Torna-ho a provar."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Canvia lleugerament la posició del cap"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira més directament al telèfon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira més directament al telèfon"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index e518de47834f..c72f07dee44c 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Umožňuje aplikaci používat služby v popředí typu „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"používat službu v popředí typu „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Umožňuje aplikaci používat služby v popředí typu „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"používat službu v popředí typu „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Umožňuje aplikaci používat služby v popředí typu „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"výpočet místa pro ukládání aplikací"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Použít zámek obrazovky"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Pokračujte zadáním zámku obrazovky"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pevně zatlačte na snímač"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Otisk prstu se nepodařilo rozpoznat. Zkuste to znovu."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Vyčistěte snímač otisků prstů a zkuste to znovu"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Vyčistěte senzor a zkuste to znovu"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pevně přitiskněte prst na snímač"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Obličej není vidět. Držte telefon v úrovni očí."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Příliš mnoho pohybu. Držte telefon nehybně."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Zaznamenejte obličej znovu."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Obličej se nepodařilo rozpoznat. Zkuste to znovu."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Mírně pohněte hlavou"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Dívejte se přímo na telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Dívejte se přímo na telefon"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index d3f8550b58c7..f72c0c2db8d3 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tillader, at appen benytter tjenester af typen \"systemExempted\" i forgrunden"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"kør tjenesten af typen \"fileManagement\" i forgrunden"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Tillader, at appen benytter tjenester af typen \"fileManagement\" i forgrunden"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kør tjenesten af typen \"specialUse\" i forgrunden"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tillader, at appen benytter tjenester af typen \"specialUse\" i forgrunden"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"måle appens lagerplads"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Brug skærmlås"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Angiv din skærmlås for at fortsætte"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Hold fingeren på sensoren"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingeraftrykket kan ikke genkendes. Prøv igen."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Rengør fingeraftrykssensoren, og prøv igen"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Rengør sensoren, og prøv igen"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Hold fingeren på sensoren"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Dit ansigt kan ikke registreres. Hold din telefon i øjenhøjde."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Der er for meget bevægelse. Hold telefonen stille."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrer dit ansigt igen."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansigtet kan ikke genkendes. Prøv igen."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Flyt dit hoved en smule"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kig mere direkte på din telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kig mere direkte på din telefon"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 514d6955e629..e03592cce867 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ermöglicht der App, Vordergrunddienste mit dem Typ „systemExempted“ zu verwenden"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Dienste im Vordergrund mit dem Typ „fileManagement“ ausführen"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Ermöglicht der App, Dienste im Vordergrund mit dem Typ „fileManagement“ zu verwenden"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Vordergrunddienste mit dem Typ „specialUse“ ausführen"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ermöglicht der App, Vordergrunddienste mit dem Typ „specialUse“ zu verwenden"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"Speicherplatz der App ermitteln"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Displaysperre verwenden"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Displaysperre eingeben, um fortzufahren"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Drücke fest auf den Sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingerabdruck wurde nicht erkannt. Versuch es noch einmal."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Reinige den Fingerabdrucksensor und versuch es noch einmal"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Reinige den Sensor und versuche es noch einmal"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Drücke fest auf den Sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Gesicht nicht erkannt. Smartphone auf Augenhöhe halten."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Zu viel Unruhe. Halte das Smartphone ruhig."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Bitte registriere dein Gesicht noch einmal."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Gesicht nicht erkannt. Versuche es noch einmal."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ändere die Position deines Kopfes leicht"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Sieh direkt auf dein Smartphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Sieh direkt auf dein Smartphone"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index a392c0fb6969..d9c94511f265 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο fileManagement."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"υπολογίζει τον αποθηκευτικό χώρο εφαρμογής"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Χρήση κλειδώματος οθόνης"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Χρησιμοποιήστε το κλείδωμα οθόνης για να συνεχίσετε"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Πιέστε σταθερά τον αισθητήρα"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"To δακτ. αποτύπωμα δεν αναγνωρίστηκε. Δοκιμάστε ξανά."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Καθαρίστε τον αισθητήρα δακτυλικών αποτυπωμάτων και δοκιμάστε ξανά"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Καθαρίστε τον αισθητήρα και δοκιμάστε ξανά"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Πιέστε σταθερά τον αισθητήρα"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Κρατήστε το τηλέφωνο στο ύψος των ματιών σας."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Πάρα πολλή κίνηση. Κρατήστε σταθερό το τηλέφωνο."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Καταχωρίστε ξανά το πρόσωπό σας."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Το πρόσωπο δεν αναγνωρίζεται. Δοκιμάστε ξανά."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Αλλάξτε ελαφρώς τη θέση του κεφαλιού σας"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Κοιτάξτε απευθείας το τηλέφωνό σας"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Κοιτάξτε απευθείας το τηλέφωνό σας"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 7498488c65be..fd801b5f710a 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"run foreground service with the type \'fileManagement\'"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Allows the app to make use of foreground services with the type \'fileManagement\'"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Press firmly on the sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Can’t recognise fingerprint. Try again."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index fd76ce577b94..bf9acc103579 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -434,6 +434,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"run foreground service with the type \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Allows the app to make use of foreground services with the type \"fileManagement\""</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"run foreground service with the type \"mediaProcessing\""</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Allows the app to make use of foreground services with the type \"mediaProcessing\""</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string> @@ -632,7 +634,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Press firmly on the sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Can’t recognize fingerprint. Try again."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string> @@ -696,7 +699,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognize face. Try again."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 1f2ccce64c86..662247ea6dc9 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"run foreground service with the type \'fileManagement\'"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Allows the app to make use of foreground services with the type \'fileManagement\'"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Press firmly on the sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Can’t recognise fingerprint. Try again."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index d4fd01e3d17b..e7278d58a7bd 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"run foreground service with the type \'fileManagement\'"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Allows the app to make use of foreground services with the type \'fileManagement\'"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Press firmly on the sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Can’t recognise fingerprint. Try again."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognise face. Try again."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index 8a89ebdfdaa7..51ab2cafd3f9 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -434,6 +434,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"run foreground service with the type \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Allows the app to make use of foreground services with the type \"fileManagement\""</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"run foreground service with the type \"mediaProcessing\""</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Allows the app to make use of foreground services with the type \"mediaProcessing\""</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string> @@ -632,7 +634,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Use screen lock"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Enter your screen lock to continue"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Press firmly on the sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Can’t recognize fingerprint. Try again."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Clean fingerprint sensor and try again"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Clean sensor and try again"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Press firmly on the sensor"</string> @@ -696,7 +699,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Can’t see your face. Hold your phone at eye level."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Too much motion. Hold phone steady."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Please re-enroll your face."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Can’t recognize face. Try again."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Change the position of your head slightly"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Look more directly at your phone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Look more directly at your phone"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index f6117cdaf253..8686e19be5c5 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que la app use servicios en primer plano con el tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Ejecutar un servicio en primer plano con el tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que la app use servicios en primer plano con el tipo \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Ejecuta un servicio en primer plano con el tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que la app use servicios en primer plano con el tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir el espacio de almacenamiento de la aplicación"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueo de pantalla"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ingresa tu bloqueo de pantalla para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Presiona el sensor con firmeza"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"No se reconoce la huella dactilar. Vuelve a intentarlo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpia el sensor de huellas dactilares y vuelve a intentarlo"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpia el sensor y vuelve a intentarlo"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Presiona el sensor con firmeza"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se te ve el rostro. Sostén el teléfono a la altura de los ojos."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te estás moviendo demasiado. No muevas el teléfono"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu rostro."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"No se reconoce el rostro. Vuelve a intentarlo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia levemente la posición de la cabeza"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira directamente al teléfono"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira directamente al teléfono"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 406f8795e2a2..8f57a078736f 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que la aplicación use servicios en primer plano con el tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"ejecutar un servicio en primer plano con el tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que la aplicación use servicios en primer plano con el tipo \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ejecutar un servicio en primer plano con el tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que la aplicación use servicios en primer plano con el tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir el espacio de almacenamiento de la aplicación"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueo de pantalla"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduce tu bloqueo de pantalla para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pulsa firmemente el sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"No se puede reconocer la huella digital. Inténtalo de nuevo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpia el sensor de huellas digitales e inténtalo de nuevo"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpia el sensor e inténtalo de nuevo"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pulsa firmemente el sensor"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"No se detecta tu cara. Sujeta el teléfono a la altura de los ojos."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"El teléfono se mueve demasiado. Mantenlo quieto."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vuelve a registrar tu cara."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"No se reconoce la cara. Inténtalo de nuevo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia ligeramente la posición de tu cabeza"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira al teléfono de forma más directa"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira al teléfono de forma más directa"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index afcc618bafd3..e814c96e217d 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „systemExempted“."</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „specialUse“."</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"Rakenduse mäluruumi mõõtmine"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekraaniluku kasutamine"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jätkamiseks sisestage oma ekraanilukk"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Vajutage kindlalt andurile"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Sõrmejälge ei õnnestu tuvastada. Proovige uuesti."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Puhastage sõrmejäljeandur ja proovige uuesti"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Puhastage andur ja proovige uuesti"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Vajutage kindlalt andurile"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Teie nägu ei ole näha. Hoidke telefoni silmade kõrgusel."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Liiga palju liikumist. Hoidke telefoni paigal."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registreerige oma nägu uuesti."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Nägu ei õnnestu tuvastada. Proovige uuesti."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Muutke pisut oma pea asendit"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Vaadake otse telefoni"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Vaadake otse telefoni"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 2b9c5550d9a4..feabc8f90fce 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Aurreko planoko zerbitzuak (systemExempted motakoak) erabiltzeko baimena ematen dio aplikazioari"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"exekutatu aurreko planoko zerbitzu bat (fileManagement motakoa)"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Aurreko planoko zerbitzuak (fileManagement motakoak) erabiltzeko baimena ematen die aplikazioei."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exekutatu aurreko planoko zerbitzu bat (specialUse motakoa)"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Aurreko planoko zerbitzuak (specialUse motakoak) erabiltzeko baimena ematen dio aplikazioari"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"neurtu aplikazioen biltegiratzeko tokia"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Erabili pantailaren blokeoa"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Aurrera egiteko, desblokeatu pantailaren blokeoa"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Sakatu irmo sentsorea"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Ezin da hauteman hatz-marka. Saiatu berriro."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Garbitu hatz-marken sentsorea eta saiatu berriro"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Garbitu sentsorea eta saiatu berriro"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Sakatu irmo sentsorea"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ezin da hauteman aurpegia. Eutsi telefonoari begien parean."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Mugimendu gehiegi dago. Eutsi tinko telefonoari."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Erregistratu berriro aurpegia."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Ezin da hauteman aurpegia. Saiatu berriro."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Aldatu buruaren posizioa apur bat"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Begiratu zuzenago telefonoari"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Begiratu zuzenago telefonoari"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index eb71a7dc3b9e..c661e95de9c7 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"به برنامه اجازه میدهد از سرویسهای پیشنما از نوع «معافیت سیستم» استفاده کند"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"اجرای سرویس پیشنما از نوع «fileManagement»"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"به برنامه اجازه میدهد از سرویسهای پیشنما از نوع «fileManagement» استفاده کند"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"اجرای سرویس پیشنما از نوع «استفاده ویژه»"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"به برنامه اجازه میدهد از سرویسهای پیشنما از نوع «استفاده ویژه» استفاده کند"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"اندازهگیری اندازه فضای ذخیرهسازی برنامه"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"از قفل صفحه استفاده کنید"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"برای ادامه، قفل صفحهتان را وارد کنید"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"محکم روی حسگر فشار دهید"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"اثر انگشت شناسایی نشد. دوباره امتحان کنید."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"حسگر اثر انگشت را تمیز و دوباره امتحان کنید"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"حسگر را تمیز و دوباره امتحان کنید"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"محکم روی حسگر فشار دهید"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"چهره دیده نمیشود. تلفن را همسطح چشمانتان نگه دارید."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"حرکت خیلی زیاد است. تلفن را ثابت نگهدارید."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"لطفاً چهرهتان را مجدداً ثبت کنید."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"چهره شناسایی نشد. دوباره امتحان کنید."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"موقعیت سرتان را کمی تغییر دهید"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"مستقیمتر به تلفن نگاه کنید"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"مستقیمتر به تلفن نگاه کنید"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 8359bf6aecff..9aad9fa6b15e 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"käyttää etualan palveluja, joiden tyyppi on \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"käyttää etualan palveluja, joiden tyyppi on \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"sovellusten tallennustilan mittaaminen"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Käytä näytön lukitusta"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jatka lisäämällä näytön lukituksen avaustapa"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Paina anturia voimakkaasti"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Sormenjälkeä ei voi tunnistaa. Yritä uudelleen."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Puhdista sormenjälkitunnistin ja yritä uudelleen"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Puhdista anturi ja yritä uudelleen"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Paina tunnistinta voimakkaasti"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kasvoja ei näy. Pidä puhelinta silmien korkeudella."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Laite liikkui liikaa. Pidä puhelin vakaana."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Rekisteröi kasvot uudelleen."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Kasvoja ei voi tunnistaa. Yritä uudelleen."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Liikuta päätä hieman"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Katso suoremmin puhelimeen"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Katso suoremmin puhelimeen"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 8842ae8ce8f3..7be3041cdc5f 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « système exempté »"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"exécuter le service d\'avant-plan avec le type « fileManagement »"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Autorise l\'application à utiliser les services d\'avant-plan avec le type « fileManagement »"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exécuter le service d\'avant-plan avec le type « usage spécial »"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « usage spécial »"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'application"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utiliser le verrouillage de l\'écran"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Entrez votre verrouillage d\'écran pour continuer"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Appuyez fermement sur le capteur"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Empreinte digitale non reconnue. Réessayez."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Nettoyez le capteur d\'empreintes digitales et réessayez"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Nettoyez le capteur et réessayez"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Appuyez fermement sur le capteur"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Visage non détecté. Tenez votre téléphone à hauteur des yeux."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Trop de mouvement. Tenez le téléphone immobile."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Veuillez inscrire votre visage à nouveau."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Visage non reconnu. Réessayez."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Modifiez légèrement la position de votre tête"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Regardez droit dans le téléphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Regardez droit dans le téléphone"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 3b242309e9b7..f6e669c0ece4 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autorise l\'appli à utiliser les services de premier plan avec le type \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"exécuter un service de premier plan avec le type \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Autorise l\'appli à utiliser les services de premier plan avec le type \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exécuter un service de premier plan avec le type \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autorise l\'appli à utiliser les services de premier plan avec le type \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'application"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Utiliser verrouillage écran"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Utilisez le verrouillage de l\'écran pour continuer"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Appuyez fermement sur le lecteur"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impossible de reconnaître l\'empreinte digitale. Réessayez."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Nettoyez le lecteur d\'empreinte digitale et réessayez"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Nettoyez le lecteur et réessayez"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Appuyez fermement sur le lecteur"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Visage non détecté. Tenez votre téléphone à hauteur des yeux."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Trop de mouvement. Ne bougez pas le téléphone."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Veuillez enregistrer à nouveau votre visage."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Visage non reconnu. Réessayez."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Déplacez légèrement votre tête."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mettez-vous bien de face et regardez le téléphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mettez-vous bien de face et regardez le téléphone"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 703ed7ccad2f..98560f3e880e 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"executar servizo en primeiro plano co tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar servizo en primeiro plano co tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espazo de almacenamento da aplicación"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar credencial do dispositivo"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Desbloquea a pantalla para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Preme o sensor con firmeza"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Non se puido recoñecer a impresión dixital. Téntao de novo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpa o sensor de impresión dixital e téntao de novo"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpa o sensor e téntao de novo"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Preme o sensor con firmeza"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Non se che ve a cara. Pon o teléfono diante dos ollos"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Demasiado movemento. Non movas o teléfono."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Volve rexistrar a túa cara."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Non se recoñeceu a cara. Téntao de novo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia lixeiramente a posición da cabeza"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Mira o teléfono de forma máis directa"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Mira o teléfono de forma máis directa"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 2e1f0e6cfe23..9d292017e833 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ઍપને \"systemExempted\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"ઍપને \"fileManagement\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ઍપને \"specialUse\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ઍપ્લિકેશન સંગ્રહ સ્થાન માપો"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"સ્ક્રીન લૉકનો ઉપયોગ કરો"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"આગળ વધવા માટે તમારું સ્ક્રીન લૉક દાખલ કરો"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"સેન્સર પર જોરથી દબાવો"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ફિંગરપ્રિન્ટ ઓળખી શકતા નથી. ફરી પ્રયાસ કરો."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ફિંગરપ્રિન્ટ સેન્સર સાફ કરો અને ફરી પ્રયાસ કરો"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"સેન્સર સાફ કરો અને ફરી પ્રયાસ કરો"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"સેન્સર પર જોરથી દબાવો"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"તમારો ચહેરો દેખાતો નથી. તમારા ફોનને આંખના લેવલ પર પકડી રાખો."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ડિવાઇસ અસ્થિર છે. ફોનને સ્થિર રાખો."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"કૃપા કરીને તમારા ચહેરાની ફરી નોંધણી કરાવો."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ચહેરો ઓળખી શકતા નથી. ફરી પ્રયાસ કરો."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"તમારા માથાની સ્થિતિ સહેજ બદલો"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"વધારે પ્રમાણમાં સીધું તમારા ફોન તરફ જુઓ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"વધારે પ્રમાણમાં સીધું તમારા ફોન તરફ જુઓ"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 336d998ccd18..084b9568ea4a 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"इससे ऐप्लिकेशन, \"systemExempted\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"इससे ऐप्लिकेशन को \"fileManagement\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल करने की अनुमति मिलती है"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"इससे ऐप्लिकेशन, \"specialUse\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"पता करें कि ऐप मेमोरी में कितनी जगह है"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"जारी रखने के लिए, अपने स्क्रीन लॉक की पुष्टि करें"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेंसर को उंगली से ज़ोर से दबाएं"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फ़िंगरप्रिंट की पहचान नहीं की जा सकी. फिर से कोशिश करें."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फ़िंगरप्रिंट सेंसर को साफ़ करके फिर से कोशिश करें"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"फ़िंगरप्रिंट सेंसर को साफ़ करके फिर से कोशिश करें"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेंसर को उंगली से दबाकर रखें"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"आपका चेहरा नहीं दिख रहा है. फ़ोन को अपनी आंखों की सीध में रखें."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"डिवाइस बहुत ज़्यादा हिल रहा है. फ़ोन को बिना हिलाएं पकड़ें."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया फिर से अपने चेहरे की पहचान कराएं."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"चेहरे की पहचान नहीं हुई. फिर से कोशिश करें."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"अपने सिर की पोज़िशन को थोड़ा बदलें"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"अपने फ़ोन की तरफ़ बिलकुल सीधा देखें"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"अपने फ़ोन की तरफ़ बिलकुल सीधा देखें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index ec5a77e0c10d..ca57b682f0f8 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"izuzeo sustav\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"pokreni uslugu u prednjem planu s vrstom fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Aplikaciji omogućuje da iskoristi usluge u prednjem planu s vrstom fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokretanje usluge u prednjem planu s vrstom \"posebna upotreba\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"posebna upotreba\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mjerenje prostora za pohranu aplikacije"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Upotreba zaključavanja zaslona"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Upotrijebite zaključavanje zaslona da biste nastavili"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Čvrsto pritisnite senzor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Prepoznavanje otiska prsta nije uspjelo. Pokušajte ponovo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite senzor otiska prsta i pokušajte ponovno"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite senzor i pokušajte ponovno"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Čvrsto pritisnite senzor"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Vaše se lice ne vidi. Držite telefon u razini očiju."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Previše kretanja. Držite telefon mirno."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ponovo registrirajte svoje lice."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Prepoznavanje lica nije uspjelo. Pokušajte ponovo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Malo pomaknite glavu"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Gledajte ravno u telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Gledajte ravno u telefon"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 3bcd44be0ffc..2ccacffdaa14 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „systemExempted”"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"előtérben lévő szolgáltatás futtatása a következő típussal: „fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Lehetővé teszi az alkalmazásnak az előtérben futó szolgáltatások használatát a következő típussal: „fileManagement”"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"előtérben lévő szolgáltatás futtatása a következő típussal: „specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „specialUse”"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"alkalmazás-tárhely felmérése"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Képernyőzár használata"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"A folytatáshoz adja meg a képernyőzár hitelesítési adatait"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Nyomja meg határozottan az érzékelőt"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Az ujjlenyomat nem ismerhető fel. Próbálkozzon újra."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Tisztítsa meg az ujjlenyomat-érzékelőt, majd próbálja újra"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Tisztítsa meg az érzékelőt, majd próbálja újra"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Nyomja meg határozottan az érzékelőt"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nem látszik az arca. Tartsa szemmagasságban a telefonját."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Túl sok a mozgás. Tartsa stabilan a telefont."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Rögzítsen újra képet az arcáról."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Az arc nem felismerhető. Próbálja újra."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Egy kicsit mozdítsa el a fejét"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Nézzen egyenesen a telefonjára"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Nézzen egyenesen a telefonjára"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 603d7c6332ee..9480cc55222b 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Հավելվածին թույլ է տալիս օգտագործել systemExempted տեսակով ակտիվ ծառայությունները"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"fileManagement տեսակով ակտիվ ծառայությունների գործարկում"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Թույլատրում է հավելվածին օգտագործել fileManagement տեսակով ակտիվ ծառայությունները"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"գործարկել specialUse տեսակով ակտիվ ծառայությունները"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Հավելվածին թույլ է տալիս օգտագործել specialUse տեսակով ակտիվ ծառայությունները"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"չափել հավելվածի պահոցի տարածքը"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Էկրանի կողպում"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Շարունակելու համար ապակողպեք էկրանը"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Մատը ուժեղ սեղմեք սկաների վրա"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Մատնահետքը չի հաջողվում ճանաչել։ Նորից փորձեք։"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Մաքրեք մատնահետքերի սկաները և նորից փորձեք"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Մաքրեք սկաները և նորից փորձեք"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Մատը ուժեղ սեղմեք սկաների վրա"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Դեմքը չի երևում։ Հեռախոսը պահեք աչքերի մակարդակում։"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Շատ եք շարժում։ Հեռախոսն անշարժ պահեք։"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Նորից փորձեք։"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Դեմքը չի հաջողվում ճանաչել։ Նորից փորձեք։"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Թեթևակի փոխեք գլխի դիրքը"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Նայեք ուղիղ էկրանին"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Նայեք ուղիղ էկրանին"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 788628074812..50ef6a0659c2 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"menjalankan layanan latar depan dengan jenis \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"menjalankan layanan latar depan dengan jenis \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mengukur ruang penyimpanan aplikasi"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gunakan kunci layar"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Masukkan kunci layar untuk melanjutkan"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Tekan sensor dengan kuat"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Tidak dapat mengenali sidik jari. Coba lagi."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Bersihkan sensor sidik jari lalu coba lagi"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Bersihkan sensor lalu coba lagi"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Tekan sensor dengan kuat"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Wajah tidak terlihat. Pegang ponsel sejajar mata."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Terlalu banyak gerakan. Stabilkan ponsel."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Daftarkan ulang wajah Anda."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Tidak dapat mengenali wajah. Coba lagi."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ubah sedikit posisi kepala"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Lihat lebih lurus ke arah ponsel"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Lihat lebih lurus ke arah ponsel"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index ddf60c12e400..804f1319e6c0 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"keyra forgrunnsþjónustu af gerðinni „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Leyfir forritinu að nota forgrunnsþjónustur af gerðinni „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"keyra forgrunnsþjónustu af gerðinni „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mæla geymslurými forrits"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Nota skjálás"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Sláðu inn skjálásinn þinn til að halda áfram"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Ýttu ákveðið á lesarann"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingrafar þekkist ekki. Reyndu aftur."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Hreinsaðu fingrafaralesarann og reyndu aftur"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Hreinsaðu lesarann og reyndu aftur"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Ýttu ákveðið á lesarann"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Sé ekki andlitið á þér. Haltu símanum í augnhæð."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Of mikil hreyfing. Haltu símanum stöðugum."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Skráðu nafnið þitt aftur."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Andlit þekkist ekki. Reyndu aftur."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Færðu höfuðið aðeins til"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Horfðu beint á símann"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Horfðu beint á símann"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 3877ac48d00f..c1ef0ea2fdbd 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Consente all\'app di usare i servizi in primo piano con il tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Eseguire servizi in primo piano con il tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Consente all\'app di usare i servizi in primo piano con il tipo \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Esecuzione di servizi in primo piano con il tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Consente all\'app di usare i servizi in primo piano con il tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"calcolo spazio di archiviazione applicazioni"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usa il blocco schermo"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Inserisci il blocco schermo per continuare"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Premi con decisione sul sensore"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impossibile riconoscere l\'impronta. Riprova."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Pulisci il sensore di impronte digitali e riprova"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Pulisci il sensore e riprova"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Premi con decisione sul sensore"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Volto non visibile. Tieni lo smartphone all\'altezza degli occhi."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Troppo movimento. Tieni fermo il telefono."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Ripeti l\'acquisizione del volto."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Impossibile riconoscere il volto. Riprova."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Cambia leggermente la posizione della testa"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Guarda dritto nello smartphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Guarda dritto nello smartphone"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index eb2f3b2dc6eb..c1892186c9c0 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"הפעלת שירות שפועל בחזית מסוג \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"ההרשאה הזו מאפשרת לאפליקציה להתבסס על שירותים שפועלים בחזית מסוג \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"הפעלת שירות שפועל בחזית מסוג \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"מדידת נפח האחסון של אפליקציות"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"שימוש בנעילת מסך"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"יש לבטל את נעילת המסך כדי להמשיך"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"צריך ללחוץ לחיצה חזקה על החיישן"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"לא ניתן לזהות את טביעת האצבע. יש לנסות שוב."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"עליך לנקות את חיישן טביעות האצבע ולנסות שוב"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"עליך לנקות את החיישן ולנסות שוב"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"צריך ללחוץ חזק על החיישן"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"לא רואים את הפנים שלך. יש להחזיק את הטלפון בגובה העיניים."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"יותר מדי תנועה. יש להחזיק את הטלפון בצורה יציבה."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"יש לסרוק שוב את הפנים."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"לא ניתן לזהות את הפנים. יש לנסות שוב."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"צריך לשנות מעט את תנוחת הראש"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"צריך להביט ישירות בטלפון"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"צריך להביט ישירות בטלפון"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index a2d40afb5a38..7bb322cc6c37 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"タイプが「systemExempted」のフォアグラウンド サービスの使用をアプリに許可します"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"タイプが「fileManagement」のフォアグラウンド サービスの実行"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"タイプが「fileManagement」のフォアグラウンド サービスの使用をアプリに許可します"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"タイプが「specialUse」のフォアグラウンド サービスの実行"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"タイプが「specialUse」のフォアグラウンド サービスの使用をアプリに許可します"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"アプリのストレージ容量の計測"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"画面ロックの使用"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"続行するには画面ロックを入力してください"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"センサーにしっかりと押し当ててください"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"指紋を認識できません。もう一度お試しください。"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"指紋認証センサーの汚れを取り除いて、もう一度お試しください"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"センサーの汚れを取り除いて、もう一度お試しください"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"センサーにしっかりと押し当ててください"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"顔を確認できません。スマートフォンを目の高さに合わせます。"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"あまり動かさないでください。安定させてください。"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"顔を登録し直してください。"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"顔を認識できません。もう一度お試しください。"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"顔の位置を少し変えてください"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"もっとまっすぐスマートフォンに顔を向けてください"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"もっとまっすぐスマートフォンに顔を向けてください"</string> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index dee1f1f33339..7b7f267c6898 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „გათავისუფლებულისისტემა“ შემთხვევაში"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"პრიორიტეტული სერვისის გაშვება ტიპის „ფაილებისმართვა“ შემთხვევაში"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"საშუალებას აძლევს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „ფაილისმართვა“ შემთხვევაში"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"პრიორიტეტული სერვისის გაშვება ტიპის „სპეციალურიგამოყენება“ შემთხვევაში"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „სპეციალურიგამოყენება“ შემთხვევაში"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"აპის მეხსიერების სივრცის გაზომვა"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"გამოიყენეთ ეკრანის დაბლოკვა"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"გასაგრძელებლად შედით ეკრანის დაბლოკვაში"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"მაგრად დააჭირეთ სენსორს"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"თითის ანაბეჭდის ამოცნობა ვერ ხერხდება. ცადეთ ხელახლა."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"გაწმინდეთ თითის ანაბეჭდის სენსორი და ხელახლა ცადეთ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"გაწმინდეთ სენსორი და ხელახლა ცადეთ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"მაგრად დააჭირეთ სენსორს"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"სახე არ ჩანს. დაიჭირეთ ტელ. თვალის დონეზე."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"მეტისმეტად მოძრაობთ. მყარად დაიჭირეთ ტელეფონი."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"გთხოვთ, ხელახლა დაარეგისტრიროთ თქვენი სახე."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"სახის ამოცნობა ვერ ხერხდება. ცადეთ ხელახლა."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ოდნავ შეცვალეთ თავის პოზიცია"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"პირდაპირ უყურეთ ტელეფონს"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"პირდაპირ უყურეთ ტელეფონს"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 4cf61ac9b248..fa2a798b5663 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Қолданбаға \"systemExempted\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" түрі бар экрандық режимдегі қызметті іске қосу"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Қолданбаға \"fileManagement\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" түріне жататын экрандық режимдегі қызметті іске қосу"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Қолданбаға \"specialUse\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"қолданба жадындағы бос орынды өлшеу"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Экран құлпын пайдалану"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Жалғастыру үшін экран құлпын енгізіңіз."</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Сканерді қатты басыңыз"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Саусақ ізін тану мүмкін емес. Қайталап көріңіз."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Саусақ ізін оқу сканерін тазалап, әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Сканерді тазалап, әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Сканерді қатты басыңыз"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Бетіңіз көрінбей тұр. Телефонды көз деңгейінде ұстаңыз."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Қозғалыс тым көп. Телефонды қозғалтпаңыз."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Қайта тіркеліңіз."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Бет танылмады. Қайталап көріңіз."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Басыңыздың қалпын сәл өзгертіңіз."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Телефонға тура қараңыз"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Телефонға тура қараңыз"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 7973f2a0b4fe..ab51e6efe9cf 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"វាស់ទំហំការផ្ទុកកម្មវិធី"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ប្រើការចាក់សោអេក្រង់"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"បញ្ចូលការចាក់សោអេក្រង់របស់អ្នក ដើម្បីបន្ត"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"សង្កត់លើសេនស័រឱ្យណែន"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"មិនអាចសម្គាល់ស្នាមម្រាមដៃបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"សម្អាតឧបករណ៍ចាប់ស្នាមម្រាមដៃ រួចព្យាយាមម្ដងទៀត"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"សម្អាតឧបករណ៍ចាប់សញ្ញា រួចព្យាយាមម្ដងទៀត"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"សង្កត់លើសេនស័រឱ្យណែន"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"មើលមិនឃើញមុខរបស់អ្នកទេ។ កាន់ទូរសព្ទរបស់អ្នកដាក់ត្រឹមភ្នែក។"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"មានចលនាខ្លាំងពេក។ សូមកាន់ទូរសព្ទឱ្យនឹង។"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"សូមស្កេនបញ្ចូលមុខរបស់អ្នកម្ដងទៀត។"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"មិនអាចសម្គាល់មុខបានទេ។ សូមព្យាយាមម្ដងទៀត។"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ប្ដូរទីតាំងក្បាលរបស់អ្នកតិចៗ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"មើលទូរសព្ទរបស់អ្នកឱ្យចំជាងនេះ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"មើលទូរសព្ទរបស់អ្នកឱ្យចំជាងនេះ"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 7e5e5b5b9ec9..625ade1ca12d 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ಅಪ್ಲಿಕೇಶನ್ ಸಂಗ್ರಹ ಸ್ಥಳವನ್ನು ಅಳೆಯಿರಿ"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ಮುಂದುವರಿಯಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ನಮೂದಿಸಿ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ಸೆನ್ಸರ್ ಮೇಲೆ ಗಟ್ಟಿಯಾಗಿ ಒತ್ತಿರಿ"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಗುರುತಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ಸೆನ್ಸರ್ ಸ್ವಚ್ಛಗೊಳಿಸಿ ಹಾಗೂ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ಸೆನ್ಸರ್ ಮೇಲೆ ಗಟ್ಟಿಯಾಗಿ ಒತ್ತಿರಿ"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ನಿಮ್ಮ ಮುಖ ಕಾಣಿಸುತ್ತಿಲ್ಲ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಕಣ್ಣಿನ ನೇರಕ್ಕೆ ಹಿಡಿದುಕೊಳ್ಳಿ."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ತುಂಬಾ ಅಲುಗಾಡುತ್ತಿದೆ ಫೋನ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿ ಹಿಡಿಯಿರಿ."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ನಿಮ್ಮ ತಲೆಯ ಸ್ಥಾನವನ್ನು ಸ್ವಲ್ಪ ಬದಲಾಯಿಸಿ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ನೋಡಿ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ನೋಡಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index cfc7730d8c12..a40a7f4d8562 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"앱에서 \'systemExempted\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\'fileManagement\' 유형의 포그라운드 서비스 실행"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"앱에서 \'fileManagement\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\'specialUse\' 유형의 포그라운드 서비스 실행"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"앱에서 \'specialUse\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"앱 저장공간 계산"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"화면 잠금 사용"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"계속하려면 화면 잠금용 사용자 인증 정보를 입력하세요"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"센서를 세게 누르세요"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"지문 센서를 닦은 후 다시 시도해 보세요."</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"센서를 닦은 후 다시 시도해 보세요."</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"센서를 세게 누르세요"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"얼굴이 보이지 않습니다. 눈높이에 맞춰 휴대전화를 들어 주세요"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"너무 많이 움직였습니다. 휴대전화를 흔들리지 않게 잡으세요."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"얼굴을 다시 등록해 주세요."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"얼굴을 인식할 수 없습니다. 다시 시도해 주세요."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"얼굴의 위치를 조금 변경해 주세요."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"휴대전화를 좀 더 정면에서 바라보세요."</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"휴대전화를 좀 더 정면에서 바라보세요."</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index dcdfc8020929..cfa0983e0e14 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Колдонмолорго алдынкы пландагы \"systemExempted\" түрүндөгү кызматтарды колдонууга уруксат берет"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"алдынкы пландагы \"fileManagement\" түрүндөгү кызматты аткаруу"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Колдонмолорго алдынкы пландагы \"fileManagement\" түрүндөгү кызматтарды колдонууга уруксат берет"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"алдынкы пландагы \"specialUse\" түрүндөгү кызматты аткаруу"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Колдонмолорго алдынкы пландагы \"specialUse\" түрүндөгү кызматтарды колдонууга уруксат берет"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"колдонмо сактагычынын мейкиндигин өлчөө"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Экран кулпусун колдонуу"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Улантуу үчүн экрандын кулпусун киргизиңиз"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Сенсорду катуу басыңыз"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Манжа изи таанылбай жатат. Кайра аракет кылыңыз."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Манжа изинин сенсорун тазалап, кайра аракет кылыңыз"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Сенсорду тазалап, кайра аракет кылыңыз"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Сенсорду катуу басыңыз"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Жүзүңүз көрүнбөй жатат. Телефонду маңдайыңызга кармаңыз."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Кыймылдап жибердиңиз. Телефонду түз кармаңыз."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Жүзүңүздү кайра таанытыңыз."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Жүз таанылбай жатат. Кайталаңыз."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Башыңызды бир аз буруңуз"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Телефонуңузду караңыз"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Телефонуңузду караңыз"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 49266a4b9447..653de36aca6d 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ໄດ້ຮັບການຍົກເວັ້ນຈາກລະບົບ\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຈັດການໄຟລ໌\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຈັດການໄຟລ໌\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການນຳໃຊ້ພິເສດ\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການນຳໃຊ້ພິເສດ\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ກວດສອບພື້ນທີ່ຈັດເກັບຂໍ້ມູນແອັບຯ"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ໃຊ້ການລັອກໜ້າຈໍ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ໃສ່ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອສືບຕໍ່"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ກົດຢູ່ເຊັນເຊີໃຫ້ແໜ້ນ"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ບໍ່ສາມາດຈຳແນກລາຍນິ້ວມືໄດ້. ກະລຸນາລອງໃໝ່."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ໃຫ້ອະນາໄມເຊັນເຊີລາຍນິ້ວມືແລ້ວລອງໃໝ່"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ໃຫ້ອະນາໄມເຊັນເຊີແລ້ວລອງໃໝ່"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ກົດຢູ່ເຊັນເຊີໃຫ້ແໜ້ນ"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ບໍ່ເຫັນໃບໜ້າຂອງທ່ານ. ຖືໂທລະສັບຂອງທ່ານໄວ້ໃນລະດັບສາຍຕາ."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ເຄື່ອນໄຫວຫຼາຍເກີນໄປ. ກະລຸນາຖືໂທລະສັບໄວ້ຊື່ໆ."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"ກະລຸນາລົງທະບຽນອຸປະກອນຂອງທ່ານອີກເທື່ອໜຶ່ງ."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້. ກະລຸນາລອງໃໝ່."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ປ່ຽນຕຳແໜ່ງຂອງຫົວທ່ານເລັກນ້ອຍ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ເບິ່ງຊື່ໆໄປຫາໂທລະສັບຂອງທ່ານໃຫ້ຫຼາຍຂຶ້ນ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ເບິ່ງຊື່ໆໄປຫາໂທລະສັບຂອງທ່ານໃຫ້ຫຼາຍຂຶ້ນ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index aefda2e88bed..4733552be636 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Priekinio plano paslaugos, kurios tipas „fileManagement“, vykdymas"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Leidžiama programai naudoti priekinio plano paslaugas, kurių tipas „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"paleisti priekinio plano paslaugą, kurios tipas „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"matuoti programos atmintinės vietą"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Naudoti ekrano užraktą"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Jei norite tęsti, įveskite ekrano užraktą"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Stipriai paspauskite jutiklį"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Nepavyko atpažinti kontrolinio kodo. Bandykite dar kartą."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Nuvalykite kontrolinio kodo jutiklį ir bandykite dar kartą"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Nuvalykite jutiklį ir bandykite dar kartą"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Tvirtai paspauskite jutiklį"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nepavyko pamatyti jūsų veido. Laikykite telefoną akių lygyje."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Įrenginys per daug judinamas. Nejudink. telefono."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Užregistruokite veidą iš naujo."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Veidas neatpažintas. Bandykite dar kartą."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Kaskart šiek tiek pakeiskite galvos poziciją"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Žiūrėkite tiesiai į telefoną"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Žiūrėkite tiesiai į telefoną"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index f17f02fde8d6..0f4e3f9bfddb 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"izpildīt šāda veida priekšplāna pakalpojumu: fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"izpildīt šāda veida priekšplāna pakalpojumu: specialUse"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"noteikt vietas apjomu lietotnes atmiņā"</string> @@ -633,7 +637,8 @@ <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="120359538048533695">"Lai turpinātu, ievadiet ekrāna bloķēšanas informāciju"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Stingri spiediet pirkstu pie sensora"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Nevar atpazīt pirksta nospiedumu. Mēģiniet vēlreiz."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Notīriet pirkstu nospiedumu sensoru un mēģiniet vēlreiz"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Notīriet sensoru un mēģiniet vēlreiz"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Stingri spiediet pirkstu pie sensora"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Seja nav redzama. Turiet tālruni acu līmenī."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Pārāk daudz kustību. Nekustīgi turiet tālruni."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Lūdzu, atkārtoti reģistrējiet savu seju."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Nevar atpazīt seju. Mēģiniet vēlreiz."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nedaudz mainiet galvas pozīciju."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Skatieties tieši uz tālruni"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Skatieties tieši uz tālruni"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index dbcf11f1b3b0..fd8daacb1498 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозволува апликацијата да ги користи во преден план услугите со типот „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Извршување услуга во преден план со типот „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Дозволува апликацијата да ги користи услугите во преден план со типот „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"да извршува во преден план услуга со типот „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозволува апликацијата да ги користи во преден план услугите со типот „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"измери простор за складирање на апликацијата"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Користи заклучување екран"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Внесете го заклучувањето на екранот за да продолжите"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Цврсто притиснете на сензорот"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не се препознава отпечатокот. Обидете се повторно."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Исчистете го сензорот за отпечатоци и обидете се повторно"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Исчистете го сензорот и обидете се повторно"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Цврсто притиснете на сензорот"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не се гледа ликот. Држете го телефонот во висина на очите."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Премногу движење. Држете го телефонот стабилно."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторно регистрирајте го лицето."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Не се препознава ликот. Обидете се пак."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Малку сменете ја положбата на главата"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледајте подиректно во телефонот"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледајте подиректно во телефонот"</string> @@ -1961,7 +1967,7 @@ <string name="locale_search_menu" msgid="6258090710176422934">"Пребарај"</string> <string name="app_suspended_title" msgid="888873445010322650">"Апликацијата не е достапна"</string> <string name="app_suspended_default_message" msgid="6451215678552004172">"Апликацијата <xliff:g id="APP_NAME_0">%1$s</xliff:g> не е достапна во моментов. Со ова управува <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string> - <string name="app_suspended_more_details" msgid="211260942831587014">"Дознај повеќе"</string> + <string name="app_suspended_more_details" msgid="211260942831587014">"Дознајте повеќе"</string> <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Прекини ја паузата"</string> <string name="work_mode_off_title" msgid="6367463960165135829">"Да се актив. работните аплик.?"</string> <string name="work_mode_turn_on" msgid="5316648862401307800">"Прекини ја паузата"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 68c0749f32c8..a001de325e31 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -434,6 +434,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" എന്ന തരത്തിലുള്ള ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" എന്ന തരത്തിലുള്ള ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"\"mediaProcessing\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"\"mediaProcessing\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"അപ്ലിക്കേഷൻ സംഭരണയിടം അളക്കുക"</string> @@ -632,7 +634,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"തുടരാൻ നിങ്ങളുടെ സ്ക്രീൻ ലോക്ക് നൽകുക"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"സെൻസറിൽ നന്നായി അമർത്തുക"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ഫിംഗർപ്രിന്റ് തിരിച്ചറിയാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കുക."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ഫിംഗർപ്രിന്റ് സെൻസർ വൃത്തിയാക്കിയ ശേഷം വീണ്ടും ശ്രമിക്കുക"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"സെൻസർ വൃത്തിയാക്കിയ ശേഷം വീണ്ടും ശ്രമിക്കുക"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"സെൻസറിൽ നന്നായി അമർത്തുക"</string> @@ -696,7 +699,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"മുഖം കാണുന്നില്ല. ഫോൺ കണ്ണിന് നേരെ പിടിക്കുക."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"വളരെയധികം ചലനം. ഫോൺ അനക്കാതെ നേരെ പിടിക്കുക."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യുക."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല. വീണ്ടും ശ്രമിക്കൂ."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"നിങ്ങളുടെ തലയുടെ സ്ഥാനം ചെറുതായി മാറ്റുക"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"കൂടുതൽ കൃത്യമായി ഫോണിന് നേരെ നോക്കുക"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"കൂടുതൽ കൃത്യമായി ഫോണിന് നേരെ നോക്കുക"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 97858ef2048f..16b5766e190f 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Аппад \"systemExempted\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"FileManagement\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Аппад \"fileManagement\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"SpecialUse\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Аппад \"specialUse\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"апп сангийн хэмжээг хэмжих"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Дэлгэцийн түгжээг ашиглах"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Үргэлжлүүлэхийн тулд дэлгэцийн түгжээгээ оруулна уу"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Мэдрэгч дээр чанга дарна уу"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Хурууны хээг таних боломжгүй. Дахин оролдоно уу."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Хурууны хээ мэдрэгчийг цэвэрлээд, дахин оролдоно уу"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Мэдрэгчийг цэвэрлээд, дахин оролдоно уу"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Мэдрэгч дээр чанга дарна уу"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Таны царай харагдахгүй байна. Утсаа нүднийхээ түвшинд барина уу."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Хэт их хөдөлгөөнтэй байна. Утсаа хөдөлгөөнгүй барина уу."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Нүүрээ дахин бүртгүүлнэ үү."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Царайг танихгүй байна. Дахин оролдоно уу."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Толгойныхоо байрлалыг бага зэрэг өөрчилнө үү"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Утас руугаа аль болох эгц харна уу"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Утас руугаа аль болох эгц харна уу"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index cd553a484a08..51752e33df7b 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" प्रकारासोबत अॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" प्रकारासोबत अॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" प्रकारासोबत अॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"अॅप संचयन स्थान मोजा"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रीन लॉक वापरा"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"पुढे सुरू ठेवण्यासाठी तुमचे स्क्रीन लॉक एंटर करा"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरवर जोरात प्रेस करा"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फिंगरप्रिंट ओळखता आली नाही. पुन्हा प्रयत्न करा."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिंट सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर स्वच्छ करा आणि पुन्हा प्रयत्न करा"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरवर जोरात प्रेस करा"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"तुमचा चेहरा दिसत नाही. तुमचा फोन डोळ्याच्या पातळीवर धरा."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"खूप हलत आहे. फोन स्थिर धरून ठेवा."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"तुमच्या डोक्याचे स्थान किंचित बदला"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"तुमच्या फोनकडे आणखी थेट पहा"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"तुमच्या फोनकडे आणखी थेट पहा"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 90ffb215210e..599083c277db 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"jalankan perkhidmatan latar depan dengan jenis \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Benarkan apl menggunakan perkhidmatan latar depan dengan jenis \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"jalankan perkhidmatan latar depan dengan jenis \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ukur ruang storan apl"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gunakan kunci skrin"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Masukkan kunci skrin untuk teruskan"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Tekan penderia dengan kuat"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Tidak dapat mengecam cap jari. Cuba lagi."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Bersihkan penderia cap jari dan cuba lagi"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Bersihkan penderia dan cuba lagi"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Tekan penderia dengan kuat"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Wajah tidak kelihatan. Pegang telefon pada paras mata."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Terlalu bnyk gerakan. Pegang telefon dgn stabil."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Sila daftarkan semula wajah anda."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Tidak dapat mengecam wajah. Cuba lagi."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Tukar sedikit kedudukan kepala anda"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Lihat lebih lurus pada telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Lihat lebih lurus pada telefon"</string> @@ -1016,7 +1022,7 @@ <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Lupa corak?"</string> <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Buka kunci akaun"</string> <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Terlalu banyak percubaan melukis corak"</string> - <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string> + <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Untuk membuka kunci, log masuk dengan Google Account anda."</string> <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Nama Pengguna (E-mel)"</string> <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Kata laluan"</string> <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Log masuk"</string> @@ -1667,7 +1673,7 @@ <string name="kg_invalid_puk" msgid="4809502818518963344">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string> <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Kod PIN tidak sepadan"</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Terlalu banyak percubaan melukis corak"</string> - <string name="kg_login_instructions" msgid="3619844310339066827">"Untuk membuka kunci, log masuk dengan akaun Google anda."</string> + <string name="kg_login_instructions" msgid="3619844310339066827">"Untuk membuka kunci, log masuk dengan Google Account anda."</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Nama Pengguna (E-mel)"</string> <string name="kg_login_password_hint" msgid="3330530727273164402">"Kata laluan"</string> <string name="kg_login_submit_button" msgid="893611277617096870">"Log masuk"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index fa5efa6d2344..cd7d43bf92fe 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"“fileManagement” အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"“\"fileManagement” အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"အက်ပ်သိုလှောင်မှု နေရာကို တိုင်းထွာခြင်း"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ရှေ့ဆက်ရန် သင်၏ဖန်သားပြင် လော့ခ်ချခြင်းကို ထည့်ပါ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"အာရုံခံကိရိယာပေါ်တွင် သေချာဖိပါ"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"လက်ဗွေကို မမှတ်မိပါ။ ထပ်စမ်းကြည့်ပါ။"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"လက်ဗွေ အာရုံခံကိရိယာကို သန့်ရှင်းပြီး ထပ်စမ်းကြည့်ပါ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"အာရုံခံကိရိယာကို သန့်ရှင်းပြီး ထပ်စမ်းကြည့်ပါ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"အာရုံခံကိရိယာပေါ်တွင် သေချာဖိပါ"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"သင့်မျက်နှာ မမြင်ရပါ။ ဖုန်းနှင့် မျက်စိ တစ်တန်းတည်းထားပါ။"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"လှုပ်လွန်းသည်။ ဖုန်းကို ငြိမ်ငြိမ်ကိုင်ပါ။"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"သင့်မျက်နှာကို ပြန်စာရင်းသွင်းပါ။"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"မျက်နှာကို မသိပါ။ ထပ်စမ်းကြည့်ပါ။"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ခေါင်းအနေအထားကို အနည်းငယ်ပြောင်းပါ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"သင့်ဖုန်းကို တည့်တည့်ကြည့်ပါ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"သင့်ဖုန်းကို တည့်တည့်ကြည့်ပါ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index f97e43732fe7..b77d86a78d1c 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lar appen bruke forgrunnstjenester med typen «systemExempted»"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"kjør forgrunnstjeneste med typen «fileManagement»"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Lar appen bruke forgrunnstjenester med typen «fileManagement»"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kjøre forgrunnstjeneste med typen «specialUse»"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lar appen bruke forgrunnstjenester med typen «specialUse»"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"måle lagringsplass for apper"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Bruk skjermlås"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Skriv inn skjermlåsen for å fortsette"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Trykk godt på sensoren"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingeravtrykket gjenkjennes ikke. Prøv på nytt."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Rengjør fingeravtrykkssensoren og prøv igjen"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Rengjør sensoren og prøv igjen"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Trykk godt på sensoren"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Kan ikke se ansiktet ditt. Hold telefonen i øyehøyde."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"For mye bevegelse. Hold telefonen stødig."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrer ansiktet ditt på nytt."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansiktet gjenkjennes ikke. Prøv på nytt."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Endre hodeposisjonen litt"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Se mer direkte på telefonen"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Se mer direkte på telefonen"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 99dcae018fa5..6dbeb402c0f4 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"यसले एपलाई \"systemExempted\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"यस प्रकारको \"fileManagement\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू चलाउने अनुमति"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"यसले यो एपलाई यस प्रकारको \"fileManagement\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"यसले एपलाई \"specialUse\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"एप भण्डारण ठाउँको मापन गर्नुहोस्"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"स्क्रिन लक प्रयोग गर्नुहोस्"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"जारी राख्न आफ्नो स्क्रिन लक हाल्नुहोस्"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"सेन्सरमा बेसरी थिच्नुहोस्"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"फिंगरप्रिन्ट पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"फिंगरप्रिन्ट सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"सेन्सर सफा गरेर फेरि प्रयास गर्नुहोस्"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"सेन्सरमा बेसरी थिच्नुहोस्"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"तपाईंको अनुहार देखिएन। तपाईंको फोन आफ्नो आँखाअघि राखी समात्नुहोस्।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"अत्यधिक हल्लियो। फोन स्थिर राख्नुहोस्।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्।"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"आफ्नो टाउको थोरै यताउता सार्नुहोस्"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index f0d34a58e2f3..0bd0a5937be5 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'systemExempted\'"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"service op de voorgrond van het type \'fileManagement\' uitvoeren"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'fileManagement\'."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"service op de voorgrond van het type \'specialUse\' uitvoeren"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'specialUse\'"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"opslagruimte van app meten"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Schermvergrendeling gebruiken"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Voer je schermvergrendeling in om door te gaan"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Druk stevig op de sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Vingerafdruk niet herkend. Probeer het opnieuw."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Reinig de vingerafdruksensor en probeer het opnieuw"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Reinig de sensor en probeer het opnieuw"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Druk stevig op de sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Je gezicht is niet te zien. Houd je telefoon op ooghoogte."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Te veel beweging. Houd je telefoon stil."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registreer je gezicht opnieuw."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Gezicht niet herkend. Probeer het opnieuw."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Verander de positie van je hoofd een beetje"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Kijk goed recht naar je telefoon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Kijk goed recht naar je telefoon"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index bfde6c960e53..58ab2c2cbdd3 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ଆପ୍ ଷ୍ଟୋରେଜ୍ ସ୍ଥାନର ମାପ କରନ୍ତୁ"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ସ୍କ୍ରିନ୍ ଲକ୍ ଏଣ୍ଟର୍ କରନ୍ତୁ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ସେନ୍ସର ଉପରେ ଦୃଢ଼ ଭାବେ ଦବାନ୍ତୁ"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ଟିପଚିହ୍ନକୁ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ପରିଷ୍କାର କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ସେନ୍ସରକୁ ପରିଷ୍କାର କରି ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ସେନ୍ସର ଉପରେ ଦୃଢ଼ ଭାବେ ଦବାନ୍ତୁ"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ଆପଣଙ୍କ ଫେସ ଦେଖାଯାଉନାହିଁ। ଆପଣଙ୍କ ଫୋନକୁ ଆଖି ସିଧାରେ ଧରି ରଖନ୍ତୁ।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ଅତ୍ୟଧିକ ଅସ୍ଥିର। ଫୋନ୍କୁ ସ୍ଥିର ଭାବେ ଧରନ୍ତୁ।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"ଦୟାକରି ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍ରୋଲ୍ କରନ୍ତୁ।"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ଫେସ ଚିହ୍ନଟ କରାଯାଇପାରିବ ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କର।"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ଆପଣଙ୍କ ମୁଣ୍ଡର ସ୍ଥିତି ସାମାନ୍ୟ ବଦଳାନ୍ତୁ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ଆପଣଙ୍କ ଫୋନକୁ ସମ୍ପୂର୍ଣ୍ଣ ସିଧା ଦେଖନ୍ତୁ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ଆପଣଙ୍କ ଫୋନକୁ ସମ୍ପୂର୍ଣ୍ଣ ସିଧା ଦେଖନ୍ତୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index d3901f743701..c3e4134b5325 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -85,7 +85,7 @@ <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਨੂੰ ਬਦਲ ਕੇ ਦੇਖੋ। ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ।"</string> <string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਿੰਗ ਉਪਲਬਧ ਨਹੀਂ"</string> <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ਵਾਈ-ਫਾਈ ਰਾਹੀਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ ਨਹੀਂ ਕਰ ਸਕਦੇ"</string> - <string name="notification_channel_network_alert" msgid="4788053066033851841">"ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_network_alert" msgid="4788053066033851841">"ਅਲਰਟ"</string> <string name="notification_channel_call_forward" msgid="8230490317314272406">"ਕਾਲ ਫਾਰਵਰਡਿੰਗ"</string> <string name="notification_channel_emergency_callback" msgid="54074839059123159">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਬੈਕ ਮੋਡ"</string> <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਸਥਿਤੀ"</string> @@ -279,11 +279,11 @@ <string name="notification_channel_developer_important" msgid="7197281908918789589">"ਮਹੱਤਵਪੂਰਨ ਵਿਕਾਸਕਾਰ ਸੁਨੇਹੇ"</string> <string name="notification_channel_updates" msgid="7907863984825495278">"ਅੱਪਡੇਟ"</string> <string name="notification_channel_network_status" msgid="2127687368725272809">"ਨੈੱਟਵਰਕ ਅਵਸਥਾ"</string> - <string name="notification_channel_network_alerts" msgid="6312366315654526528">"ਨੈੱਟਵਰਕ ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_network_alerts" msgid="6312366315654526528">"ਨੈੱਟਵਰਕ ਅਲਰਟ"</string> <string name="notification_channel_network_available" msgid="6083697929214165169">"ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਹੈ"</string> <string name="notification_channel_vpn" msgid="1628529026203808999">"VPN ਅਵਸਥਾ"</string> - <string name="notification_channel_device_admin" msgid="6384932669406095506">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਸੁਚੇਤਨਾਵਾਂ"</string> - <string name="notification_channel_alerts" msgid="5070241039583668427">"ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_device_admin" msgid="6384932669406095506">"ਤੁਹਾਡੇ ਆਈ.ਟੀ. ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅਲਰਟ"</string> + <string name="notification_channel_alerts" msgid="5070241039583668427">"ਅਲਰਟ"</string> <string name="notification_channel_retail_mode" msgid="3732239154256431213">"ਪ੍ਰਚੂਨ ਸਟੋਰਾਂ ਲਈ ਡੈਮੋ"</string> <string name="notification_channel_usb" msgid="1528280969406244896">"USB ਕਨੈਕਸ਼ਨ"</string> <string name="notification_channel_heavy_weight_app" msgid="17455756500828043">"ਚੱਲ ਰਹੀ ਐਪ"</string> @@ -367,7 +367,7 @@ <string name="permlab_receiveMms" msgid="4000650116674380275">"ਲਿਖਤ ਸੁਨੇਹੇ (MMS) ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="permdesc_receiveMms" msgid="958102423732219710">"ਐਪ ਨੂੰ MMS ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਕਰਨ ਅਤੇ ਉਹਨਾਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਐਪ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੇ ਭੇਜੇ ਗਏ ਸੁਨੇਹਿਆਂ ਨੂੰ ਤੁਹਾਨੂੰ ਦਿਖਾਏ ਬਿਨਾਂ ਨਿਰੀਖਣ ਕਰ ਸਕਦੀ ਹੈ ਜਾਂ ਮਿਟਾ ਸਕਦੀ ਹੈ।"</string> <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਨੂੰ ਅੱਗੇ ਭੇਜੋ"</string> - <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ਐਪ ਨੂੰ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਦੇ ਪ੍ਰਾਪਤ ਹੁੰਦੇ ਹੀ ਉਹਨਾਂ ਨੂੰ ਅੱਗੇ ਭੇਜਣ ਲਈ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਮਾਡਿਊਲ ਨਾਲ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਚੇਤਨਾਵਾਂ ਤੁਹਾਨੂੰ ਸੰਕਟਕਾਲੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਟਿਕਾਣਿਆਂ \'ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਭੈੜੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਸੰਕਟਕਾਲੀ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string> + <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ਐਪ ਨੂੰ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਦੇ ਪ੍ਰਾਪਤ ਹੁੰਦੇ ਹੀ ਉਨ੍ਹਾਂ ਨੂੰ ਅੱਗੇ ਭੇਜਣ ਲਈ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਮਾਡਿਊਲ ਨਾਲ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਅਲਰਟ ਤੁਹਾਨੂੰ ਐਮਰਜੈਂਸੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਟਿਕਾਣਿਆਂ \'ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਭੈੜੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਐਮਰਜੈਂਸੀ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string> <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ਜਾਰੀ ਕਾਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ਐਪ ਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਜਾਰੀ ਕਾਲਾਂ ਬਾਰੇ ਵੇਰਵੇ ਦੇਖਣ ਅਤੇ ਇਹਨਾਂ ਕਾਲਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਦਿਓ।"</string> <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ਸੈਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹੇ ਪੜ੍ਹੋ"</string> @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ਐਪ ਨੂੰ \"systemExempted\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਓ"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"ਐਪ ਨੂੰ \"fileManagement\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤਣ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ਐਪ ਨੂੰ \"specialUse\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ਐਪ ਸਟੋਰੇਜ ਜਗ੍ਹਾ ਮਾਪੋ"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਸਕ੍ਰੀਨ ਲਾਕ ਦਾਖਲ ਕਰੋ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"ਸੈਂਸਰ ਨੂੰ ਜ਼ੋਰ ਨਾਲ ਦਬਾਓ"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪਛਾਣ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ਸੈਂਸਰ ਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"ਸੈਂਸਰ ਨੂੰ ਜ਼ੋਰ ਨਾਲ ਦਬਾਓ"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਨਹੀਂ ਦਿਸ ਰਿਹਾ। ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਅੱਖਾਂ ਦੀ ਸੀਧ ਵਿੱਚ ਰੱਖੋ।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਹਿਲਜੁਲ। ਫ਼ੋਨ ਨੂੰ ਸਥਿਰ ਰੱਖੋ।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਚਿਹਰਾ ਦੁਬਾਰਾ ਦਰਜ ਕਰੋ।"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ਆਪਣੇ ਸਿਰ ਨੂੰ ਥੋੜ੍ਹਾ ਹਿਲਾਓ"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ਸਿੱਧਾ ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ਸਿੱਧਾ ਆਪਣੇ ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ"</string> @@ -1922,7 +1928,7 @@ <string name="stk_cc_ss_to_ss" msgid="132040645206514450">"ਨਵੀਂ SS ਬੇਨਤੀ ਵਿੱਚ ਬਦਲਿਆ ਗਿਆ"</string> <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_alerted_content_description" msgid="6139691253611265992">"ਅਲਰਟ"</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> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index e03679bbc27e..07a69e67fbd1 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „systemExempted”"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Uruchamianie usług działających na pierwszym planie typu „fileManagement”"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „fileManagement”."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"uruchamianie usług działających na pierwszym planie typu „specialUse”"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „specialUse”"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mierzenie rozmiaru pamięci aplikacji"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Używaj blokady ekranu"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Użyj blokady ekranu, aby kontynuować"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Mocno naciśnij czujnik"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Nie rozpoznaję odcisku palca. Spróbuj ponownie."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Wyczyść czytnik linii papilarnych i spróbuj ponownie"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Wyczyść czujnik i spróbuj ponownie"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Mocno naciśnij czujnik"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie widać twarzy – trzymaj telefon na wysokości oczu"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Telefon się porusza. Trzymaj go nieruchomo."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Zarejestruj swoją twarz ponownie."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Nie rozpoznaję twarzy. Spróbuj ponownie."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Lekko zmień położenie głowy"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Patrz prosto na telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Patrz prosto na telefon"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 2888c5f7e027..e29502a61258 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -435,6 +435,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que o app use serviços em primeiro plano com o tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"executar serviços em primeiro plano com o tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que o app use serviços em primeiro plano com o tipo \"fileManagement\""</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"executar serviços em primeiro plano com o tipo \"mediaProcessing\""</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Permite que o app use serviços em primeiro plano com o tipo \"mediaProcessing\""</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar serviços em primeiro plano com o tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que o app use serviços em primeiro plano com o tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espaço de armazenamento do app"</string> @@ -633,7 +635,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pressione o sensor com firmeza"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impressão digital não reconhecida. Tente de novo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressão digital e tente novamente"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pressione o sensor com firmeza"</string> @@ -697,7 +700,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Rosto não detectado. Segure o smartphone na altura dos olhos."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Muito movimento. Não mova o smartphone."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registre seu rosto novamente."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Não foi possível reconhecer o rosto. Tente de novo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Mude a posição da cabeça ligeiramente"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe diretamente para o smartphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe diretamente para o smartphone"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 7a3201fca3b3..cae02fcbb7b2 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -435,6 +435,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que a app use serviços em primeiro plano com o tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"executar o serviço em primeiro plano com o tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que a app use serviços em primeiro plano com o tipo \"fileManagement\""</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"executar o serviço em primeiro plano com o tipo \"mediaProcessing\""</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Permite que a app use serviços em primeiro plano com o tipo \"mediaProcessing\""</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar o serviço em primeiro plano com o tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que a app use serviços em primeiro plano com o tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir espaço de armazenamento da app"</string> @@ -633,7 +635,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar o bloqueio de ecrã"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduza o bloqueio de ecrã para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Prima firmemente o sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impossível reconhecer impressão digital. Volte a tentar."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressões digitais e tente novamente"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Prima firmemente o sensor"</string> @@ -697,7 +700,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Rosto não detetado. Segure o telemóvel ao nível dos olhos"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Demasiado movimento. Mantenha o telemóvel firme."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Volte a inscrever o rosto."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Impossível reconhecer o rosto. Tente novamente."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Altere ligeiramente a posição da sua cabeça"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe mais diretamente para o telemóvel"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe mais diretamente para o telemóvel"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 2888c5f7e027..e29502a61258 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -435,6 +435,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que o app use serviços em primeiro plano com o tipo \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"executar serviços em primeiro plano com o tipo \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite que o app use serviços em primeiro plano com o tipo \"fileManagement\""</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"executar serviços em primeiro plano com o tipo \"mediaProcessing\""</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"Permite que o app use serviços em primeiro plano com o tipo \"mediaProcessing\""</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar serviços em primeiro plano com o tipo \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que o app use serviços em primeiro plano com o tipo \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espaço de armazenamento do app"</string> @@ -633,7 +635,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Usar bloqueio de tela"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Insira seu bloqueio de tela para continuar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pressione o sensor com firmeza"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Impressão digital não reconhecida. Tente de novo."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Limpe o sensor de impressão digital e tente novamente"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Limpe o sensor e tente novamente"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pressione o sensor com firmeza"</string> @@ -697,7 +700,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Rosto não detectado. Segure o smartphone na altura dos olhos."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Muito movimento. Não mova o smartphone."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registre seu rosto novamente."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Não foi possível reconhecer o rosto. Tente de novo."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Mude a posição da cabeça ligeiramente"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Olhe diretamente para o smartphone"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Olhe diretamente para o smartphone"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 082fbb24c969..2beb190c4f28 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite aplicației să folosească serviciile în prim-plan cu tipul „systemExempted”"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"să folosească serviciile în prim-plan cu tipul „fileManagement”"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Permite aplicației să folosească serviciile în prim-plan cu tipul „fileManagement”"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"să folosească serviciile în prim-plan cu tipul „specialUse”"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite aplicației să folosească serviciile în prim-plan cu tipul „specialUse”"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"măsurare spațiu de stocare al aplicației"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Folosește blocarea ecranului"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introdu blocarea ecranului pentru a continua"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Apasă ferm pe senzor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Amprenta nu a fost recunoscută. Încearcă din nou."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Curăță senzorul de amprentă și încearcă din nou"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Curăță senzorul și încearcă din nou"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Apasă ferm pe senzor"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nu ți se vede fața. Ține telefonul la nivelul ochilor."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Prea multă mișcare. Ține telefonul nemișcat."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Reînregistrează-ți chipul."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Chipul nu a fost recunoscut. Reîncearcă."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Schimbă ușor poziția capului"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Privește mai direct spre telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Privește mai direct spre telefon"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 8a03a6b18ae7..299e445799cc 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Разрешить приложению использовать активные службы с типом systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Запуск активных служб с типом fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Приложение сможет использовать активные службы с типом fileManagement."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запускать активные службы с типом specialUse"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Разрешить приложению использовать активные службы с типом specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"Вычисление объема памяти приложений"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Использовать блокировку экрана"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Чтобы продолжить, разблокируйте экран."</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Плотно прижмите палец к сканеру"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Не удалось распознать отпечаток. Повторите попытку."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Очистите сканер отпечатков пальцев и повторите попытку."</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Очистите сканер и повторите попытку."</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Плотно прижмите палец к сканеру."</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Вашего лица не видно. Держите телефон на уровне глаз"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Не перемещайте устройство. Держите его неподвижно."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторите попытку."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Не удалось распознать лицо. Повторите попытку."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Немного измените положение головы"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Смотрите прямо на телефон"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Смотрите прямо на телефон"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 89ee9f910257..e19231e42d52 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"යෙදුම් ආචයනයේ ඉඩ ප්රමාණය මැනීම"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"තිර අගුල භාවිත කරන්න"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ඉදිරියට යාමට ඔබගේ තිර අගුල ඇතුළත් කරන්න"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"සංවේදකය මත තදින් ඔබන්න"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ඇඟිලි සලකුණ හඳුනා ගත නොහැක. නැවත උත්සාහ කරන්න."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ඇඟිලි සලකුණු සංවේදකය පිරිසිදු කර නැවත උත්සාහ කරන්න"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"සංවේදකය පිරිසිදු කර නැවත උත්සාහ කරන්න"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"සංවේදකය මත තදින් ඔබන්න"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ඔබගේ මුහුණ දැකිය නොහැකිය. ඔබගේ දුරකථනය ඇස් මට්ටමින් අල්ලා ගන්න."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"චලනය ඉතා වැඩියි. දුරකථනය ස්ථිරව අල්ලා සිටින්න."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"ඔබේ මුහුණ යළි ලියාපදිංචි කරන්න."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"මුහුණ හඳුනා ගත නොහැකිය. නැවත උත්සාහ කරන්න."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"ඔබගේ හිසෙහි පිහිටීම මදක් වෙනස් කරන්න"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"ඔබගේ දුරකථනය දෙස වඩාත් ඍජුව බලන්න"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"ඔබගේ දුරකථනය දෙස වඩාත් ඍජුව බලන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index bbfefd162c7f..c9508ba8a7f3 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Umožňuje aplikácii využívať služby na popredí s typom dataSync systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"spúšťať službu na popredí s typom remoteMessaging"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Umožňuje aplikácii využívať služby na popredí s typom fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"spustiť službu na popredí s typom specialUse"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Umožňuje aplikácii využívať služby na popredí s typom specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"zistiť veľkosť ukladacieho priestoru aplikácie"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Použiť zámku obrazovky"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Pokračujte zadaním zámky obrazovky"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pevne pritlačte prst na senzor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Odtlačok prsta sa nedá rozpoznať. Skúste to znova."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Vyčistite senzor odtlačkov prstov a skúste to znova"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Vyčistite senzor a skúste to znova"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pevne pritlačte prst na senzor"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nie je vidieť vašu tvár. Držte telefón na úrovni očí."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Priveľa pohybu. Nehýbte telefónom."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova zaregistrujte svoju tvár."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Tvár sa nedá rozpoznať. Skúste to znova."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Trocha zmeňte pozíciu hlavy"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Pozrite sa na telefón priamejšie"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Pozrite sa na telefón priamejšie"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index e4e9a37fdc36..c459fdb720df 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »systemExempted«."</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"izvajanje storitve v ospredju vrste »fileManagement«"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »fileManagement«."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"izvajanje storitve v ospredju vrste »specialUse«"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »specialUse«."</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"izračunavanje prostora za shranjevanje aplikacije"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Uporaba odklepanja s poverilnico"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Odklenite zaslon, če želite nadaljevati."</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Prst dobro pridržite na tipalu"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Prstnega odtisa ni mogoče prepoznati. Poskusite znova."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Očistite tipalo prstnih odtisov in poskusite znova."</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Očistite tipalo in poskusite znova."</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Prst dobro pridržite na tipalu"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Obraz ni viden. Držite telefon v višini oči."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Preveč se premikate. Držite telefon pri miru."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova registrirajte svoj obraz."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Obraza ni mogoče prepoznati. Poskusite znova."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nekoliko spremenite položaj glave."</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Glejte bolj naravnost v telefon"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Glejte bolj naravnost v telefon"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 288d8bf5acf9..a62dddb7772a 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"ekzekuto shërbimin në plan të parë me llojin \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Lejon aplikacionin të përdorë shërbimet në plan të parë me llojin \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"të ekzekutojë shërbimin në plan të parë me llojin \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mat hapësirën ruajtëse të aplikacionit"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Përdor kyçjen e ekranit"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fut kyçjen e ekranit për të vazhduar"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Shtyp fort te sensori"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Nuk mund ta dallojë gjurmën e gishtit. Provo përsëri."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Pastro sensorin e gjurmës së gishtit dhe provo sërish"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Pastro sensorin dhe provo sërish"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Shtyp fort te sensori"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Fytyra s\'mund të shihet. Mbaje telefonin në nivelin e syve."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ka shumë lëvizje. Mbaje telefonin të palëvizur."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Regjistroje përsëri fytyrën tënde."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Fytyra nuk mund të njihet. Provo sërish."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Ndrysho pak pozicionin e kokës"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Shiko më drejtpërdrejt telefonin"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Shiko më drejtpërdrejt telefonin"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 479a1db277ed..048d826adbff 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -435,6 +435,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „systemExempted“"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"покретање услуге у првом плану која припада типу „fileManagement“"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „fileManagement“"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"покретање услуге у првом плану која припада типу „specialUse“"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „specialUse“"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"мерење меморијског простора у апликацији"</string> @@ -633,7 +637,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Користите закључавање екрана"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Употребите закључавање екрана да бисте наставили"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Чврсто притисните сензор"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Препознавање отиска прста није успело. Пробајте поново."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Обришите сензор за отисак прста и пробајте поново"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Обришите сензор и пробајте поново"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Чврсто притисните сензор"</string> @@ -697,7 +702,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Не види се лице. Држите телефон у висини очију."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Много се померате. Држите телефон мирно."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Поново региструјте лице."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Лице није препознато. Пробајте поново."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Мало померите главу"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Гледајте право у телефон"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Гледајте право у телефон"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index a30aa0a012a6..d10cbe6a1de1 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tillåter att appen använder förgrundstjänster av typen systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"kör förgrundstjänst av typen fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Tillåter att appen använder förgrundstjänster av typen fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kör förgrundstjänst av typen specialUse"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tillåter att appen använder förgrundstjänster av typen specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"mäta appens lagringsplats"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Använd skärmlåset"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Fortsätt med hjälp av ditt skärmlås"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Tryck hårt på sensorn"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Fingeravtrycket kändes inte igen. Försök igen."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Rengör fingeravtryckssensorn och försök igen"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Rengör sensorn och försök igen"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Tryck hårt på sensorn"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ansiktet syns inte. Håll telefonen i ögonhöjd."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"För mycket rörelse. Håll mobilen stilla."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Registrera ansiktet på nytt."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Ansiktet kändes inte igen. Försök igen."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Rör lite på huvudet"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Titta rakt på telefonen"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Titta rakt på telefonen"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 9a063fb65b0f..8e1348fd238e 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Huiruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"Pima nafasi ya hifadhi ya programu"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Tumia mbinu ya kufunga skrini"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Weka mbinu yako ya kufunga skrini ili uendelee"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Bonyeza kwa uthabiti kwenye kitambuzi"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Imeshindwa kutambua alama ya kidole. Jaribu tena."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Safisha kitambua alama ya kidole kisha ujaribu tena"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Safisha kitambuzi kisha ujaribu tena"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Bonyeza kwa nguvu kwenye kitambuzi"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Imeshindwa kuona uso wako. Shikilia simu ikilingana na macho."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Inatikisika sana. Ishike simu iwe thabiti."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Tafadhali sajili uso wako tena."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Imeshindwa kutambua uso. Jaribu tena."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Badilisha nafasi ya kichwa chako kidogo"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Angalia simu yako moja kwa moja"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Angalia simu yako moja kwa moja"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 23402f7e38a5..32fb6a433c70 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ஆப்ஸ் சேமிப்பு இடத்தை அளவிடல்"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"திரைப் பூட்டைப் பயன்படுத்து"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"தொடர்வதற்கு உங்கள் திரைப் பூட்டை உள்ளிடுங்கள்"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"சென்சாரின் மீது நன்றாக அழுத்தவும்"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"கைரேகையை அடையாளம் காண முடியவில்லை. மீண்டும் முயலவும்."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"கைரேகை சென்சாரைச் சுத்தம் செய்துவிட்டு மீண்டும் முயலவும்"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"சென்சாரைச் சுத்தம் செய்துவிட்டு மீண்டும் முயலவும்"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"சென்சாரின் மீது நன்றாக அழுத்தவும்"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"முகம் சரியாகத் தெரியவில்லை. மொபைலைக் கண்களுக்கு நேராகப் பிடிக்கவும்."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"அதிகமாக அசைகிறது. மொபைலை அசைக்காமல் பிடிக்கவும்."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"உங்கள் முகத்தை மீண்டும் பதிவுசெய்யுங்கள்."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"முகத்தை அடையாளம் காண இயலவில்லை. மீண்டும் முயலவும்."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"தலையின் நிலையைச் சிறிதளவு மாற்றவும்"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"உங்கள் மொபைலை நேராகப் பார்க்கவும்"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"உங்கள் மொபைலை நேராகப் பார்க்கவும்"</string> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index 30697b34e357..3f98b25eaad1 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -434,6 +434,8 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" అనే రకంతో ఫోర్గ్రౌండ్ సర్వీస్లను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" రకంతో ఫోర్గ్రౌండ్ సర్వీస్ను రన్ చేయండి"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"\"fileManagement\" అనే రకంతో ఫోర్గ్రౌండ్ సర్వీస్లను ఉపయోగించుకోవడానికి యాప్ను అనుమతిస్తుంది"</string> + <string name="permlab_foregroundServiceMediaProcessing" msgid="3045295152245381864">"\"mediaProcessing\" రకంతో ఫోర్గ్రౌండ్ సర్వీస్ను రన్ చేయండి"</string> + <string name="permdesc_foregroundServiceMediaProcessing" msgid="8303086172106677312">"\"mediaProcessing\" అనే రకంతో ఫోర్గ్రౌండ్ సర్వీస్లను ఉపయోగించుకోవడానికి యాప్ను అనుమతిస్తుంది"</string> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" రకంతో ఫోర్గ్రౌండ్ సర్వీస్ను రన్ చేయండి"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" అనే రకంతో ఫోర్గ్రౌండ్ సర్వీస్లను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"యాప్ స్టోరేజ్ స్థలాన్ని అంచనా వేయడం"</string> @@ -632,7 +634,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"స్క్రీన్ లాక్ను ఉపయోగించండి"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"కొనసాగించడానికి మీ స్క్రీన్ లాక్ను ఎంటర్ చేయండి"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"సెన్సార్ మీద గట్టిగా నొక్కండి"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"వేలిముద్రను గుర్తించడం సాధ్యపడదు. మళ్లీ ట్రై చేయండి."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"వేలిముద్ర సెన్సార్ను క్లీన్ చేసి, మళ్లీ ట్రై చేయండి"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"సెన్సార్ను క్లీన్ చేసి, మళ్లీ ట్రై చేయండి"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"సెన్సార్ మీద గట్టిగా నొక్కండి"</string> @@ -696,7 +699,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"మీ ముఖం కనిపించడం లేదు. మీ ఫోన్ను కళ్లకు ఎదురుగా పట్టుకోండి."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"బాగా కదుపుతున్నారు. ఫోన్ను స్థిరంగా పట్టుకోండి"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"దయచేసి మీ ముఖాన్ని మళ్లీ నమోదు చేయండి."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ముఖం గుర్తించబడలేదు. మళ్లీ ట్రై చేయండి."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"మీ తల స్థానాన్ని కొద్దిగా మార్చండి"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"మీ ఫోన్ వైపు మరింత నేరుగా చూడండి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 66ed0539cb5e..81fa17769c02 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ได้รับการยกเว้นจากระบบ\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การจัดการไฟล์\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การจัดการไฟล์\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การใช้งานพิเศษ\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การใช้งานพิเศษ\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"ใช้การล็อกหน้าจอ"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"ป้อนข้อมูลการล็อกหน้าจอเพื่อดำเนินการต่อ"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"กดเซ็นเซอร์ให้แน่น"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"ไม่รู้จักลายนิ้วมือ โปรดลองอีกครั้ง"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"ทำความสะอาดเซ็นเซอร์ลายนิ้วมือแล้วลองอีกครั้ง"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"ทำความสะอาดเซ็นเซอร์แล้วลองอีกครั้ง"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"กดเซ็นเซอร์ให้แน่น"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"ไม่เห็นใบหน้า ถือโทรศัพท์ไว้ที่ระดับสายตา"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"มีการเคลื่อนไหวมากเกินไป ถือโทรศัพท์นิ่งๆ"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"โปรดลงทะเบียนใบหน้าอีกครั้ง"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"ไม่รู้จักใบหน้า โปรดลองอีกครั้ง"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"เปลี่ยนตำแหน่งของศีรษะเล็กน้อย"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"โปรดมองตรงมาที่โทรศัพท์"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"โปรดมองตรงมาที่โทรศัพท์"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index c83daa31e372..8009e0cc6584 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"Magpatakbo ng serbisyo sa foreground na may uring \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"magpagana ng serbisyo sa foreground na may uring \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"sukatin ang espasyo ng storage ng app"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Gumamit ng lock ng screen"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ilagay ang iyong lock ng screen para magpatuloy"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Pumindot nang madiin sa sensor"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Hindi makilala ang fingerprint. Subukan ulit."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Linisin ang sensor para sa fingerprint at subukan ulit"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Linisin ang sensor at subukan ulit"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Pumindot nang madiin sa sensor"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Hindi makita ang mukha mo. Hawakan ang telepono kapantay ng mata."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Masyadong magalaw. Hawakang mabuti ang telepono."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Paki-enroll muli ang iyong mukha."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Hindi makilala ang mukha. Subukan ulit."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Bahagyang baguhin ang posisyon ng iyong ulo"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Tumingin nang mas direkta sa iyong telepono"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Tumingin nang mas direkta sa iyong telepono"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index c2c8ec655610..18f46ee4f933 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Uygulamanın \"systemExempted\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" türündeki ön plan hizmetini çalıştırma"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Uygulamanın \"fileManagement\" türündeki ön plan hizmetlerini kullanmasına izin verir."</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" türüyle ön plan hizmetini çalıştırma"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Uygulamanın \"specialUse\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"uygulama depolama alanını ölç"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran kilidi kullan"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Devam etmek için ekran kilidinizi girin"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Sensöre sıkıca bastırın"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Parmak izi tanınamadı. Tekrar deneyin."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Parmak izi sensörünü temizleyip tekrar deneyin"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Sensörü temizleyip tekrar deneyin"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Sensöre sıkıca bastırın"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Yüzünüz görünmüyor. Telefonunuzu göz hizasında tutun."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Çok fazla hareket ediyorsunuz. Telefonu sabit tutun."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Lütfen yüzünüzü yeniden kaydedin."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Yüz tanınamadı. Tekrar deneyin."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Başınızın konumunu hafifçe değiştirin"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonunuza daha doğrudan bakın"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonunuza daha doğrudan bakın"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 00139a635826..88a3b2bc60f4 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -436,6 +436,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозволяє додатку використовувати активні сервіси типу systemExempted"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"запускати активний сервіс типу fileManagement"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Дозволяє додатку використовувати активні сервіси типу fileManagement"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запускати сервіс типу specialUse в активному режимі"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозволяє додатку використовувати активні сервіси типу specialUse"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"визначати об’єм пам’яті програми"</string> @@ -634,7 +638,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Доступ розблокуванням екрана"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Щоб продовжити, введіть дані для розблокування екрана"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Міцно притисніть палець до сканера"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Відбиток пальця не розпізнано. Повторіть спробу."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Очистьте сканер відбитків пальців і повторіть спробу"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Очистьте сканер і повторіть спробу"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Міцно притисніть палець до сканера"</string> @@ -698,7 +703,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Обличчя не видно. Утримуйте телефон на рівні очей."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Забагато рухів. Тримайте телефон нерухомо."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Повторно проскануйте обличчя."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Обличчя не розпізнано. Повторіть спробу."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Трохи змініть положення голови"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Дивіться на телефон прямо"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Дивіться на телефон прямо"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index dc3ca4752c75..267351a05e93 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ایپ کو \"systemExempted\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"\"fileManagement\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"ایپ کو \"fileManagement\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ایپ کو \"specialUse\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ایپ اسٹوریج کی جگہ کی پیمائش کریں"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"اسکرین لاک استعمال کریں"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"جاری رکھنے کے لیے اپنا اسکرین لاک درج کریں"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"سینسر پر اچھی طرح دبائیں"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"فنگر پرنٹ کی شناخت نہیں کی جا سکی۔ دوبارہ کوشش کریں۔"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"فنگر پرنٹ سینسر صاف کریں اور دوبارہ کوشش کریں"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"سینسر صاف کریں اور دوبارہ کوشش کریں"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"سینسر پر اچھی طرح دبائیں"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"آپ کا چہرہ دکھائی نہیں دے رہا۔ اپنے فون کو آنکھ کی سطح پر پکڑیں۔"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"کافی حرکت ہو رہی ہے۔ فون کو مضبوطی سے پکڑیں۔"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"براہ کرم اپنے چہرے کو دوبارہ مندرج کریں۔"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"چہرے کی شناخت نہیں ہو سکی۔ پھر کوشش کریں۔"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"اپنے سر کی پوزیشن کو تھوڑا تبدیل کریں"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"اپنے فون کی طرف چہرے کو سیدھا رکھیں"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"اپنے فون کی طرف چہرے کو سیدھا رکھیں"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 23ef54caaa9f..d739e8b3a193 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ilovaga “systemExempted” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"“fileManagement” turidagi faol xizmatni ishga tushirish"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Ilovaga “fileManagement” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"“specialUse” turidagi faol xizmatni ishga tushirish"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ilovaga “specialUse” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ilovalar egallagan xotira joyini hisoblash"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Ekran qulfi"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Ekran qulfini kiritish bilan davom eting"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Sensorni mahkam bosing"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Bu barmoq izi notanish. Qayta urining."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Barmoq izi skanerini tozalang va qayta urining"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Sensorni tozalang va qayta urining"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Sensorni mahkam bosing"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Yuz koʻrinmayapti. Telefonni koʻz darajasida tuting."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ortiqcha harakatlanmoqda. Qimirlatmasdan ushlang."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Yuzingizni qaytadan qayd qildiring."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Yuz aniqlanmadi. Qayta urining."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Boshingiz holatini biroz oʻzgartiring"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Telefonga tik qarab turing"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Telefonga tik qarab turing"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 22d9f068b343..15f7f8fea88d 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"chạy dịch vụ trên nền trước thuộc loại \"fileManagement\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"fileManagement\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"chạy dịch vụ trên nền trước thuộc loại \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"đo dung lượng lưu trữ ứng dụng"</string> @@ -632,7 +636,8 @@ <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="120359538048533695">"Hãy nhập phương thức khóa màn hình của bạn để tiếp tục"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Ấn mạnh lên cảm biến"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Không nhận dạng được vân tay. Hãy thử lại."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Hãy vệ sinh cảm biến vân tay rồi thử lại"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Vệ sinh cảm biến rồi thử lại"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Ấn mạnh lên cảm biến"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Không thấy khuôn mặt. Hãy cầm điện thoại ngang tầm mắt."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Thiết bị di chuyển quá nhiều. Giữ yên thiết bị."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Vui lòng đăng ký lại khuôn mặt của bạn."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Không thể nhận dạng khuôn mặt. Hãy thử lại."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Nghiêng đầu của bạn một chút"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Nhìn thẳng vào điện thoại"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Nhìn thẳng vào điện thoại"</string> diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml index af305329da1a..31acd9af164c 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -90,4 +90,7 @@ {@link MotionEvent#AXIS_SCROLL} generated by {@link InputDevice#SOURCE_ROTARY_ENCODER} devices. --> <bool name="config_viewRotaryEncoderHapticScrollFedbackEnabled">true</bool> + + <!-- If this is true, allow wake from theater mode from motion. --> + <bool name="config_allowTheaterModeWakeFromMotion">true</bool> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index dec4705a255d..91fdc945575e 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允许该应用使用“systemExempted”类型的前台服务"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"运行“fileManagement”类型的前台服务"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"允许该应用使用“fileManagement”类型的前台服务"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"运行“specialUse”类型的前台服务"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允许该应用使用“specialUse”类型的前台服务"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"计算应用存储空间"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用屏幕锁定凭据"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"输入您的屏幕锁定凭据才能继续"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"请用力按住传感器"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"无法识别指纹,请重试。"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"请清洁指纹传感器,然后重试"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"请清洁传感器,然后重试"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"请用力按住传感器"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"看不到您的脸,请将手机举到与眼睛齐平的位置。"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"摄像头过于晃动。请将手机拿稳。"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"请重新注册您的面孔。"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"无法识别人脸,请重试。"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"请略微调整头部的位置"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"请尽量直视手机"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"请尽量直视手机"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 769c274c11e3..3fe3061760d7 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允許應用程式配搭「systemExempted」類型使用前景服務"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"配搭「fileManagement」類型執行前景服務"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"允許應用程式配搭「fileManagement」類型使用前景服務"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"配搭「specialUse」類型執行前景服務"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允許應用程式配搭「specialUse」類型使用前景服務"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"測量應用程式儲存空間"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定解鎖憑證"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"請用力按住感應器"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"無法辨識指紋,請再試一次。"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"請清潔指紋感應器,然後再試一次"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"請清潔感應器,然後再試一次"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"請用力按住感應器"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"看不到面孔,請將手機放在視線水平。"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"裝置不夠穩定。請拿穩手機。"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊面孔。"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"無法辨識面孔,請再試一次。"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"請稍為轉換頭部的位置"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"正面望向手機"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"正面望向手機"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 2c8c0465a4bf..4f6ef2857981 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允許應用程式搭配「systemExempted」類型使用前景服務"</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"搭配「fileManagement」類型執行前景服務"</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"允許應用程式搭配「fileManagement」類型使用前景服務"</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"搭配「specialUse」類型執行前景服務"</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允許應用程式搭配「specialUse」類型使用前景服務"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"測量應用程式儲存空間"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"使用螢幕鎖定功能"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"如要繼續操作,請輸入螢幕鎖定憑證"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"請確實按住感應器"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"無法辨識指紋,請再試一次。"</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"請清潔指紋感應器,然後再試一次"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"清潔感應器,然後再試一次"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"請確實按住感應器"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"未偵測到你的臉,請將手機舉到與眼睛同高的位置。"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"鏡頭過度晃動,請拿穩手機。"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊你的臉孔。"</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"無法辨識這張臉,請再試一次。"</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"請稍微改變頭部位置"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"請盡可能直視手機"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"請盡可能直視手機"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 42f0b3ffb8be..d5ce2adc8093 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -434,6 +434,10 @@ <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"systemExempted\""</string> <string name="permlab_foregroundServiceFileManagement" msgid="2585000987966045030">"qalisa isevisi ephambili ngohlobo lokuthi \"Ikholi yefoni\""</string> <string name="permdesc_foregroundServiceFileManagement" msgid="417103601269698508">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lwe-\"systemExempted\""</string> + <!-- no translation found for permlab_foregroundServiceMediaProcessing (3045295152245381864) --> + <skip /> + <!-- no translation found for permdesc_foregroundServiceMediaProcessing (8303086172106677312) --> + <skip /> <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"qalisa isevisi ephambili ngohlobo lokuthi \"specialUse\""</string> <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"specialUse\""</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"linganisa isikhala sokugcina uhlelo lokusebenza"</string> @@ -632,7 +636,8 @@ <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Sebenzisa isikhiya sesikrini"</string> <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Faka ukukhiya isikrini kwakho ukuze uqhubeke"</string> <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Cindezela inzwa uqinise"</string> - <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Ayisazi isigxivizo somunwe. Zama futhi."</string> + <!-- no translation found for fingerprint_acquired_insufficient (2410176550915730974) --> + <skip /> <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Hlanza inzwa yesigxivizo somunwe bese uzame futhi"</string> <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Hlanza inzwa bese uzame futhi"</string> <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Cindezela inzwa uqinise"</string> @@ -696,7 +701,8 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"Ayikwazi ukubona ubuso bakho. Bamba ifoni yakho iqondane namehlo"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Ukunyakaza okuningi kakhulu. Bamba ifoni iqine."</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Sicela uphinde ubhalise ubuso bakho."</string> - <string name="face_acquired_too_different" msgid="2520389515612972889">"Ayikwazi ukubona ubuso. Zama futhi."</string> + <!-- no translation found for face_acquired_too_different (4505278456634706967) --> + <skip /> <string name="face_acquired_too_similar" msgid="8882920552674125694">"Shintsha indawo yekhanda lakho kancane"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Bheka ngqo kakhulu kufoni yakho"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Bheka ngqo kakhulu kufoni yakho"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 8fae6db4114a..601952437650 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -506,6 +506,12 @@ receivers, and providers; it can not be used with activities. --> <attr name="singleUser" format="boolean" /> + <!-- If set to true, only a single instance of this component will + run and be available for the SYSTEM user. Non SYSTEM users will not be + allowed to access the component if this flag is enabled. + This flag can be used with services, receivers, providers and activities. --> + <attr name="systemUserOnly" format="boolean" /> + <!-- Specify a specific process that the associated code is to run in. Use with the application tag (to supply a default process for all application components), or with the activity, receiver, service, @@ -2859,6 +2865,7 @@ Context.createAttributionContext() using the first attribution tag contained here. --> <attr name="attributionTags" /> + <attr name="systemUserOnly" format="boolean" /> </declare-styleable> <!-- Attributes that can be supplied in an AndroidManifest.xml @@ -3017,6 +3024,7 @@ ignored when the process is bound into a shared isolated process by a client. --> <attr name="allowSharedIsolatedProcess" format="boolean" /> + <attr name="systemUserOnly" format="boolean" /> </declare-styleable> <!-- @hide The <code>apex-system-service</code> tag declares an apex system service @@ -3144,7 +3152,7 @@ <attr name="uiOptions" /> <attr name="parentActivityName" /> <attr name="singleUser" /> - <!-- @hide This broadcast receiver or activity will only receive broadcasts for the + <!-- This broadcast receiver or activity will only receive broadcasts for the system user--> <attr name="systemUserOnly" format="boolean" /> <attr name="persistableMode" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 806be9471ae5..5be29a6d68b8 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2349,6 +2349,8 @@ <string name="config_defaultCallRedirection" translatable="false"></string> <!-- The name of the package that will hold the call screening role by default. --> <string name="config_defaultCallScreening" translatable="false"></string> + <!-- The name of the package that will hold the wallet role by default. --> + <string name="config_defaultWallet" translatable="false" /> <!-- The name of the package that will hold the system gallery role. --> <string name="config_systemGallery" translatable="false">com.android.gallery3d</string> <!-- The names of the packages that will hold the automotive projection role. --> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 17bb86a7c423..7b5c49c8d9aa 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -119,6 +119,8 @@ <public name="optional"/> <!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") --> <public name="adServiceTypes" /> + <!-- @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") --> + <public name="systemUserOnly"/> </staging-public-group> <staging-public-group type="id" first-id="0x01bc0000"> @@ -130,6 +132,8 @@ <staging-public-group type="string" first-id="0x01ba0000"> <!-- @hide @SystemApi @FlaggedApi("android.permission.flags.retail_demo_role_enabled") --> <public name="config_defaultRetailDemo" /> + <!-- @hide @SystemApi @FlaggedApi("android.permission.flags.wallet_role_enabled") --> + <public name="config_defaultWallet" /> </staging-public-group> <staging-public-group type="dimen" first-id="0x01b90000"> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 542e9d6f936f..f2858066b55b 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1825,7 +1825,7 @@ <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized --> <string name="fingerprint_acquired_partial">Press firmly on the sensor</string> <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized --> - <string name="fingerprint_acquired_insufficient">Can\u2019t recognize fingerprint. Try again.</string> + <string name="fingerprint_acquired_insufficient">Fingerprint not recognized. Try again.</string> <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning --> <string name="fingerprint_acquired_imager_dirty">Clean fingerprint sensor and try again</string> <string name="fingerprint_acquired_imager_dirty_alt">Clean sensor and try again</string> @@ -1959,7 +1959,7 @@ <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] --> <string name="face_acquired_recalibrate">Please re-enroll your face.</string> <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] --> - <string name="face_acquired_too_different">Can\u2019t recognize face. Try again.</string> + <string name="face_acquired_too_different">Face not recognized. Try again.</string> <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] --> <string name="face_acquired_too_similar">Change the position of your head slightly</string> <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] --> diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java index bd5f809dc689..e118c98dd4da 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java @@ -255,6 +255,7 @@ public class SQLiteDatabaseTest { final String query = "--comment\nSELECT count(*) from t1"; + database.beginTransactionReadOnly(); try { for (int i = count; i > 0; i--) { ticker.arriveAndAwaitAdvance(); @@ -268,6 +269,7 @@ public class SQLiteDatabaseTest { } catch (Throwable t) { errors.add(t); } finally { + database.endTransaction(); ticker.arriveAndDeregister(); } } diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java index bf56df1c9441..0dec756d7611 100644 --- a/core/tests/coretests/src/android/graphics/PaintTest.java +++ b/core/tests/coretests/src/android/graphics/PaintTest.java @@ -19,6 +19,7 @@ package android.graphics; import static org.junit.Assert.assertNotEquals; import android.test.InstrumentationTestCase; +import android.text.TextUtils; import androidx.test.filters.SmallTest; @@ -362,4 +363,44 @@ public class PaintTest extends InstrumentationTestCase { // = 30 assertEquals(30.0f, p.getUnderlineThickness(), 0.5f); } + + private int getClusterCount(Paint p, String text) { + Paint.RunInfo runInfo = new Paint.RunInfo(); + p.getRunCharacterAdvance(text, 0, text.length(), 0, text.length(), false, 0, null, 0, null, + runInfo); + int ccByString = runInfo.getClusterCount(); + runInfo.setClusterCount(0); + char[] buf = new char[text.length()]; + TextUtils.getChars(text, 0, text.length(), buf, 0); + p.getRunCharacterAdvance(buf, 0, buf.length, 0, buf.length, false, 0, null, 0, null, + runInfo); + int ccByChars = runInfo.getClusterCount(); + assertEquals(ccByChars, ccByString); + return ccByChars; + } + + public void testCluster() { + final Paint p = new Paint(); + p.setTextSize(100); + + // Regular String + assertEquals(1, getClusterCount(p, "A")); + assertEquals(2, getClusterCount(p, "AB")); + + // Ligature is in the same cluster + assertEquals(1, getClusterCount(p, "fi")); // Ligature + p.setFontFeatureSettings("'liga' off"); + assertEquals(2, getClusterCount(p, "fi")); // Ligature is disabled + p.setFontFeatureSettings(""); + + // Combining character + assertEquals(1, getClusterCount(p, "\u0061\u0300")); // A + COMBINING GRAVE ACCENT + + // BiDi + final String rtlStr = "\u05D0\u05D1\u05D2"; + final String ltrStr = "abc"; + assertEquals(3, getClusterCount(p, rtlStr)); + assertEquals(6, getClusterCount(p, rtlStr + ltrStr)); + assertEquals(9, getClusterCount(p, ltrStr + rtlStr + ltrStr)); + } } diff --git a/core/tests/coretests/src/android/os/BuildTest.java b/core/tests/coretests/src/android/os/BuildTest.java index 3162e6da15c5..2d3e12331e23 100644 --- a/core/tests/coretests/src/android/os/BuildTest.java +++ b/core/tests/coretests/src/android/os/BuildTest.java @@ -45,7 +45,8 @@ public class BuildTest { public final RavenwoodRule mRavenwood = new RavenwoodRule(); @Rule - public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule( + SetFlagsRule.DefaultInitValueType.NULL_DEFAULT); /** * Asserts that a String is non-null and non-empty. If it is not, diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java index 12a28446b0e1..a28bb69244eb 100644 --- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java +++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java @@ -195,9 +195,30 @@ public class PerformanceHintManagerTest { Session s = createSession(); assumeNotNull(s); s.updateTargetWorkDuration(16); - s.reportActualWorkDuration(new WorkDuration(1, 12, 8, 6)); - s.reportActualWorkDuration(new WorkDuration(1, 33, 14, 20)); - s.reportActualWorkDuration(new WorkDuration(1, 14, 10, 6)); + { + WorkDuration workDuration = new WorkDuration(); + workDuration.setWorkPeriodStartTimestampNanos(1); + workDuration.setActualTotalDurationNanos(12); + workDuration.setActualCpuDurationNanos(8); + workDuration.setActualGpuDurationNanos(6); + s.reportActualWorkDuration(workDuration); + } + { + WorkDuration workDuration = new WorkDuration(); + workDuration.setWorkPeriodStartTimestampNanos(1); + workDuration.setActualTotalDurationNanos(33); + workDuration.setActualCpuDurationNanos(14); + workDuration.setActualGpuDurationNanos(20); + s.reportActualWorkDuration(workDuration); + } + { + WorkDuration workDuration = new WorkDuration(); + workDuration.setWorkPeriodStartTimestampNanos(1); + workDuration.setActualTotalDurationNanos(14); + workDuration.setActualCpuDurationNanos(10); + workDuration.setActualGpuDurationNanos(6); + s.reportActualWorkDuration(workDuration); + } } @Test @@ -206,25 +227,25 @@ public class PerformanceHintManagerTest { assumeNotNull(s); s.updateTargetWorkDuration(16); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(-1, 12, 8, 6)); + s.reportActualWorkDuration(new WorkDuration(-1, 12, 8, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(0, 12, 8, 6)); + s.reportActualWorkDuration(new WorkDuration(0, 12, 8, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(1, -1, 8, 6)); + s.reportActualWorkDuration(new WorkDuration(1, -1, 8, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(1, 0, 8, 6)); + s.reportActualWorkDuration(new WorkDuration(1, 0, 8, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6)); + s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6)); + s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6, 1)); }); assertThrows(IllegalArgumentException.class, () -> { - s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1)); + s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1, 1)); }); } } diff --git a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java new file mode 100644 index 000000000000..c70da6e94385 --- /dev/null +++ b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 The Android Open 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 org.junit.Assert.assertThrows; + +import android.platform.test.annotations.IgnoreUnderRavenwood; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.platform.test.ravenwood.RavenwoodRule; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@IgnoreUnderRavenwood(blockedBy = WorkDuration.class) +public class WorkDurationUnitTest { + @Rule + public final RavenwoodRule mRavenwood = new RavenwoodRule(); + + // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect. + @Rule + public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood() ? null + : DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION) + public void testWorkDurationSetters_IllegalArgument() { + WorkDuration workDuration = new WorkDuration(); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setWorkPeriodStartTimestampNanos(-1); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setWorkPeriodStartTimestampNanos(0); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setActualTotalDurationNanos(-1); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setActualTotalDurationNanos(0); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setActualCpuDurationNanos(-1); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setActualCpuDurationNanos(0); + }); + assertThrows(IllegalArgumentException.class, () -> { + workDuration.setActualGpuDurationNanos(-1); + }); + } +} diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java index 34842a0b7597..a31992c8cfa1 100644 --- a/core/tests/coretests/src/android/text/TextLineTest.java +++ b/core/tests/coretests/src/android/text/TextLineTest.java @@ -50,11 +50,11 @@ public class TextLineTest { tl.set(paint, line, 0, line.length(), Layout.DIR_LEFT_TO_RIGHT, Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */, 0, 0 /* no ellipsis */, false /* useFallbackLinespace */); - final float originalWidth = tl.metrics(null, null, false); + final float originalWidth = tl.metrics(null, null, false, null); final float expandedWidth = 2 * originalWidth; tl.justify(expandedWidth); - final float newWidth = tl.metrics(null, null, false); + final float newWidth = tl.metrics(null, null, false, null); TextLine.recycle(tl); return Math.abs(newWidth - expandedWidth) < 0.5; } @@ -128,7 +128,7 @@ public class TextLineTest { private void assertMeasurements(final TextLine tl, final int length, boolean trailing, final float[] expected) { for (int offset = 0; offset <= length; ++offset) { - assertEquals(expected[offset], tl.measure(offset, trailing, null, null), 0.0f); + assertEquals(expected[offset], tl.measure(offset, trailing, null, null, null), 0.0f); } final boolean[] trailings = new boolean[length + 1]; @@ -318,7 +318,7 @@ public class TextLineTest { tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */, 9, 12, false /* useFallbackLineSpacing */); - tl.measure(text.length(), false /* trailing */, null /* fmi */, null); + tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); assertFalse(span.mIsUsed); } @@ -335,7 +335,7 @@ public class TextLineTest { tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */, 9, 12, false /* useFallbackLineSpacing */); - tl.measure(text.length(), false /* trailing */, null /* fmi */, null); + tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); assertTrue(span.mIsUsed); } @@ -352,7 +352,7 @@ public class TextLineTest { tl.set(new TextPaint(), text, 0, text.length(), 1, Layout.DIRS_ALL_LEFT_TO_RIGHT, false /* hasTabs */, null /* tabStops */, 9, 12, false /* useFallbackLineSpacing */); - tl.measure(text.length(), false /* trailing */, null /* fmi */, null); + tl.measure(text.length(), false /* trailing */, null /* fmi */, null, null); assertTrue(span.mIsUsed); } diff --git a/core/tests/nfctests/OWNERS b/core/tests/nfctests/OWNERS deleted file mode 100644 index 34b095c7fda0..000000000000 --- a/core/tests/nfctests/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /core/java/android/nfc/OWNERS diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index dcc96861bc31..fbe1b8e65171 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -48,6 +48,7 @@ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> <permission name="android.permission.READ_SEARCH_INDEXABLES"/> <permission name="android.permission.REBOOT"/> + <permission name="android.permission.RECOVERY"/> <permission name="android.permission.STATUS_BAR"/> <permission name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"/> <permission name="android.permission.TETHER_PRIVILEGED"/> diff --git a/data/keyboards/Vendor_0957_Product_0031.idc b/data/keyboards/Vendor_0957_Product_0031.idc new file mode 100644 index 000000000000..f0320c8a78d4 --- /dev/null +++ b/data/keyboards/Vendor_0957_Product_0031.idc @@ -0,0 +1,21 @@ +# Copyright 2024 The Android Open 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. +# PID 0031 is for old GPIO pin + +# Basic Parameters +keyboard.doNotWakeByDefault = 1 +audio.mic = 1
\ No newline at end of file diff --git a/data/keyboards/Vendor_0957_Product_0034.idc b/data/keyboards/Vendor_0957_Product_0034.idc new file mode 100644 index 000000000000..52ed0bc74fd4 --- /dev/null +++ b/data/keyboards/Vendor_0957_Product_0034.idc @@ -0,0 +1,23 @@ +# Copyright 2024 The Android Open 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. +# PID 0034 is for new GPIO pin PCB. + +# Basic Parameters +keyboard.layout = Vendor_0957_Product_0031 +# The reason why we set is follow https://docs.partner.android.com/tv/build/gtv/boot-resume +keyboard.doNotWakeByDefault = 1 +audio.mic = 1
\ No newline at end of file diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index f10cdb82022e..c5a2f983ae00 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -65,6 +65,8 @@ public class Paint { private long mNativeShader; private long mNativeColorFilter; + private static boolean sIsRobolectric = Build.FINGERPRINT.equals("robolectric"); + // Use a Holder to allow static initialization of Paint in the boot image. private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = @@ -2474,6 +2476,19 @@ public class Paint { nGetFontMetricsInt(mNativePaint, metrics, true); } + /** @hide */ + public static final class RunInfo { + private int mClusterCount = 0; + + public int getClusterCount() { + return mClusterCount; + } + + public void setClusterCount(int clusterCount) { + mClusterCount = clusterCount; + } + } + /** * Return the recommend line spacing based on the current typeface and * text size. @@ -3320,7 +3335,7 @@ public class Paint { int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex) { return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset, - advances, advancesIndex, null); + advances, advancesIndex, null, null); } /** @@ -3339,12 +3354,14 @@ public class Paint { * @param advances the array that receives the computed character advances * @param advancesIndex the start index from which the advances array is filled * @param drawBounds the output parameter for the bounding box of drawing text, optional + * @param runInfo the output parameter for storing run information. * @return width measurement between start and offset - * @hide + * @hide TODO: Reorganize APIs */ public float getRunCharacterAdvance(@NonNull char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, - @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds) { + @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, + @Nullable RunInfo runInfo) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -3370,11 +3387,19 @@ public class Paint { } if (end == start) { + if (runInfo != null) { + runInfo.setClusterCount(0); + } return 0.0f; } - return nGetRunCharacterAdvance(mNativePaint, text, start, end, contextStart, contextEnd, - isRtl, offset, advances, advancesIndex, drawBounds); + if (sIsRobolectric) { + return nGetRunCharacterAdvance(mNativePaint, text, start, end, + contextStart, contextEnd, isRtl, offset, advances, advancesIndex, drawBounds); + } else { + return nGetRunCharacterAdvance(mNativePaint, text, start, end, contextStart, contextEnd, + isRtl, offset, advances, advancesIndex, drawBounds, runInfo); + } } /** @@ -3402,7 +3427,7 @@ public class Paint { int contextStart, int contextEnd, boolean isRtl, int offset, @Nullable float[] advances, int advancesIndex) { return getRunCharacterAdvance(text, start, end, contextStart, contextEnd, isRtl, offset, - advances, advancesIndex, null); + advances, advancesIndex, null, null); } /** @@ -3418,12 +3443,14 @@ public class Paint { * @param advances the array that receives the computed character advances * @param advancesIndex the start index from which the advances array is filled * @param drawBounds the output parameter for the bounding box of drawing text, optional + * @param runInfo an optional output parameter for filling run information. * @return width measurement between start and offset - * @hide + * @hide TODO: Reorganize APIs */ public float getRunCharacterAdvance(@NonNull CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, - @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds) { + @Nullable float[] advances, int advancesIndex, @Nullable RectF drawBounds, + @Nullable RunInfo runInfo) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } @@ -3456,7 +3483,7 @@ public class Paint { TextUtils.getChars(text, contextStart, contextEnd, buf, 0); final float result = getRunCharacterAdvance(buf, start - contextStart, end - contextStart, 0, contextEnd - contextStart, isRtl, offset - contextStart, - advances, advancesIndex, drawBounds); + advances, advancesIndex, drawBounds, runInfo); TemporaryBuffer.recycle(buf); return result; } @@ -3574,7 +3601,7 @@ public class Paint { int contextStart, int contextEnd, boolean isRtl, int offset); private static native float nGetRunCharacterAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, float[] advances, - int advancesIndex, RectF drawingBounds); + int advancesIndex, RectF drawingBounds, RunInfo runInfo); private static native int nGetOffsetForAdvance(long paintPtr, char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance); private static native void nGetFontMetricsIntForText(long paintPtr, char[] text, @@ -3729,4 +3756,11 @@ public class Paint { private static native void nSetTextSize(long paintPtr, float textSize); @CriticalNative private static native boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr); + + + // Following Native methods are kept for old Robolectric JNI signature used by + // SystemUIGoogleRoboRNGTests + private static native float nGetRunCharacterAdvance(long paintPtr, char[] text, + int start, int end, int contextStart, int contextEnd, boolean isRtl, int offset, + float[] advances, int advancesIndex, RectF drawingBounds); } diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 5ad144d50b87..45540e0fbbb8 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -175,3 +175,74 @@ android_library { plugins: ["dagger2-compiler"], use_resource_processor: true, } + +android_app { + name: "WindowManagerShellRobolectric", + platform_apis: true, + static_libs: [ + "WindowManager-Shell", + ], + manifest: "multivalentTests/AndroidManifestRobolectric.xml", + use_resource_processor: true, +} + +android_robolectric_test { + name: "WMShellRobolectricTests", + instrumentation_for: "WindowManagerShellRobolectric", + upstream: true, + java_resource_dirs: [ + "multivalentTests/robolectric/config", + ], + srcs: [ + "multivalentTests/src/**/*.kt", + ], + static_libs: [ + "junit", + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "mockito-robolectric-prebuilt", + "mockito-kotlin2", + "truth", + ], +} + +android_test { + name: "WMShellMultivalentTestsOnDevice", + srcs: [ + "multivalentTests/src/**/*.kt", + ], + static_libs: [ + "WindowManager-Shell", + "junit", + "androidx.test.runner", + "androidx.test.rules", + "androidx.test.ext.junit", + "frameworks-base-testutils", + "mockito-kotlin2", + "mockito-target-extended-minus-junit4", + "truth", + "platform-test-annotations", + "platform-test-rules", + ], + libs: [ + "android.test.base", + "android.test.runner", + ], + jni_libs: [ + "libdexmakerjvmtiagent", + "libstaticjvmtiagent", + ], + kotlincflags: ["-Xjvm-default=all"], + optimize: { + enabled: false, + }, + test_suites: ["device-tests"], + platform_apis: true, + certificate: "platform", + aaptflags: [ + "--extra-packages", + "com.android.wm.shell", + ], + manifest: "multivalentTests/AndroidManifest.xml", +} diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml new file mode 100644 index 000000000000..f8f8338e5f04 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml @@ -0,0 +1,13 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.wm.shell.multivalenttests"> + + <application android:debuggable="true" android:supportsRtl="true" > + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation + android:name="androidx.test.runner.AndroidJUnitRunner" + android:label="Multivalent tests for WindowManager-Shell" + android:targetPackage="com.android.wm.shell.multivalenttests"> + </instrumentation> +</manifest> diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml new file mode 100644 index 000000000000..ffcd7d46fbae --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml @@ -0,0 +1,3 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.wm.shell.multivalenttests"> +</manifest> diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml b/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml new file mode 100644 index 000000000000..36fe8ec3370d --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<configuration description="Runs Tests for WindowManagerShellLib"> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="install-arg" value="-t" /> + <option name="test-file-name" value="WMShellMultivalentTestsOnDevice.apk" /> + </target_preparer> + + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="framework-base-presubmit" /> + <option name="test-tag" value="WMShellMultivalentTestsOnDevice" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="com.android.wm.shell.multivalenttests" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false"/> + </test> +</configuration> diff --git a/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties b/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties new file mode 100644 index 000000000000..7a0527ccaafb --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties @@ -0,0 +1,2 @@ +sdk=NEWEST_SDK + diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt new file mode 100644 index 000000000000..ea7c6edd4b56 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt @@ -0,0 +1,481 @@ +/* + * Copyright (C) 2023 The Android Open 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.bubbles + +import android.content.Context +import android.content.Intent +import android.content.pm.ShortcutInfo +import android.graphics.Insets +import android.graphics.PointF +import android.graphics.Rect +import android.os.UserHandle +import android.view.WindowManager +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.wm.shell.R +import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT +import com.google.common.truth.Truth.assertThat +import com.google.common.util.concurrent.MoreExecutors.directExecutor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** Tests operations and the resulting state managed by [BubblePositioner]. */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class BubblePositionerTest { + + private lateinit var positioner: BubblePositioner + private val context = ApplicationProvider.getApplicationContext<Context>() + private val defaultDeviceConfig = + DeviceConfig( + windowBounds = Rect(0, 0, 1000, 2000), + isLargeScreen = false, + isSmallTablet = false, + isLandscape = false, + isRtl = false, + insets = Insets.of(0, 0, 0, 0) + ) + + @Before + fun setUp() { + val windowManager = context.getSystemService(WindowManager::class.java) + positioner = BubblePositioner(context, windowManager) + } + + @Test + fun testUpdate() { + val insets = Insets.of(10, 20, 5, 15) + val screenBounds = Rect(0, 0, 1000, 1200) + val availableRect = Rect(screenBounds) + availableRect.inset(insets) + positioner.update(defaultDeviceConfig.copy(insets = insets, windowBounds = screenBounds)) + assertThat(positioner.availableRect).isEqualTo(availableRect) + assertThat(positioner.isLandscape).isFalse() + assertThat(positioner.isLargeScreen).isFalse() + assertThat(positioner.insets).isEqualTo(insets) + } + + @Test + fun testShowBubblesVertically_phonePortrait() { + positioner.update(defaultDeviceConfig) + assertThat(positioner.showBubblesVertically()).isFalse() + } + + @Test + fun testShowBubblesVertically_phoneLandscape() { + positioner.update(defaultDeviceConfig.copy(isLandscape = true)) + assertThat(positioner.isLandscape).isTrue() + assertThat(positioner.showBubblesVertically()).isTrue() + } + + @Test + fun testShowBubblesVertically_tablet() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) + assertThat(positioner.showBubblesVertically()).isTrue() + } + + /** If a resting position hasn't been set, calling it will return the default position. */ + @Test + fun testGetRestingPosition_returnsDefaultPosition() { + positioner.update(defaultDeviceConfig) + val restingPosition = positioner.getRestingPosition() + val defaultPosition = positioner.defaultStartPosition + assertThat(restingPosition).isEqualTo(defaultPosition) + } + + /** If a resting position has been set, it'll return that instead of the default position. */ + @Test + fun testGetRestingPosition_returnsRestingPosition() { + positioner.update(defaultDeviceConfig) + val restingPosition = PointF(100f, 100f) + positioner.restingPosition = restingPosition + assertThat(positioner.getRestingPosition()).isEqualTo(restingPosition) + } + + /** Test that the default resting position on phone is in upper left. */ + @Test + fun testGetRestingPosition_bubble_onPhone() { + positioner.update(defaultDeviceConfig) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val restingPosition = positioner.getRestingPosition() + assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) + assertThat(restingPosition.y).isEqualTo(defaultYPosition) + } + + @Test + fun testGetRestingPosition_bubble_onPhone_RTL() { + positioner.update(defaultDeviceConfig.copy(isRtl = true)) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val restingPosition = positioner.getRestingPosition() + assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) + assertThat(restingPosition.y).isEqualTo(defaultYPosition) + } + + /** Test that the default resting position on tablet is middle left. */ + @Test + fun testGetRestingPosition_chatBubble_onTablet() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val restingPosition = positioner.getRestingPosition() + assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left) + assertThat(restingPosition.y).isEqualTo(defaultYPosition) + } + + @Test + fun testGetRestingPosition_chatBubble_onTablet_RTL() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val restingPosition = positioner.getRestingPosition() + assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right) + assertThat(restingPosition.y).isEqualTo(defaultYPosition) + } + + /** Test that the default resting position on tablet is middle right. */ + @Test + fun testGetDefaultPosition_appBubble_onTablet() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true)) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) + assertThat(startPosition.x).isEqualTo(allowableStackRegion.right) + assertThat(startPosition.y).isEqualTo(defaultYPosition) + } + + @Test + fun testGetRestingPosition_appBubble_onTablet_RTL() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) + val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */) + assertThat(startPosition.x).isEqualTo(allowableStackRegion.left) + assertThat(startPosition.y).isEqualTo(defaultYPosition) + } + + @Test + fun testHasUserModifiedDefaultPosition_false() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) + assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() + positioner.restingPosition = positioner.defaultStartPosition + assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() + } + + @Test + fun testHasUserModifiedDefaultPosition_true() { + positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true)) + assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse() + positioner.restingPosition = PointF(0f, 100f) + assertThat(positioner.hasUserModifiedDefaultPosition()).isTrue() + } + + @Test + fun testGetExpandedViewHeight_max() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT) + } + + @Test + fun testGetExpandedViewHeight_customHeight_valid() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + val minHeight = + context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) + val bubble = + Bubble( + "key", + ShortcutInfo.Builder(context, "id").build(), + minHeight + 100 /* desiredHeight */, + 0 /* desiredHeightResId */, + "title", + 0 /* taskId */, + null /* locus */, + true /* isDismissable */, + directExecutor()) {} + + // Ensure the height is the same as the desired value + assertThat(positioner.getExpandedViewHeight(bubble)) + .isEqualTo(bubble.getDesiredHeight(context)) + } + + @Test + fun testGetExpandedViewHeight_customHeight_tooSmall() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val bubble = + Bubble( + "key", + ShortcutInfo.Builder(context, "id").build(), + 10 /* desiredHeight */, + 0 /* desiredHeightResId */, + "title", + 0 /* taskId */, + null /* locus */, + true /* isDismissable */, + directExecutor()) {} + + // Ensure the height is the same as the desired value + val minHeight = + context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height) + assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight) + } + + @Test + fun testGetMaxExpandedViewHeight_onLargeTablet() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val manageButtonHeight = + context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) + val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) + val expandedViewPadding = + context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding) + val expectedHeight = + 1800 - 2 * 20 - manageButtonHeight - pointerWidth - expandedViewPadding * 2 + assertThat(positioner.getMaxExpandedViewHeight(false /* isOverflow */)) + .isEqualTo(expectedHeight) + } + + @Test + fun testAreBubblesBottomAligned_largeScreen_true() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + assertThat(positioner.areBubblesBottomAligned()).isTrue() + } + + @Test + fun testAreBubblesBottomAligned_largeScreen_landscape_false() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + isLandscape = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + assertThat(positioner.areBubblesBottomAligned()).isFalse() + } + + @Test + fun testAreBubblesBottomAligned_smallTablet_false() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + isSmallTablet = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + assertThat(positioner.areBubblesBottomAligned()).isFalse() + } + + @Test + fun testAreBubblesBottomAligned_phone_false() { + val deviceConfig = + defaultDeviceConfig.copy( + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + assertThat(positioner.areBubblesBottomAligned()).isFalse() + } + + @Test + fun testExpandedViewY_phoneLandscape() { + val deviceConfig = + defaultDeviceConfig.copy( + isLandscape = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + // This bubble will have max height so it'll always be top aligned + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(positioner.getExpandedViewYTopAligned()) + } + + @Test + fun testExpandedViewY_phonePortrait() { + val deviceConfig = + defaultDeviceConfig.copy( + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + // Always top aligned in phone portrait + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(positioner.getExpandedViewYTopAligned()) + } + + @Test + fun testExpandedViewY_smallTabletLandscape() { + val deviceConfig = + defaultDeviceConfig.copy( + isSmallTablet = true, + isLandscape = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + // This bubble will have max height which is always top aligned on small tablets + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(positioner.getExpandedViewYTopAligned()) + } + + @Test + fun testExpandedViewY_smallTabletPortrait() { + val deviceConfig = + defaultDeviceConfig.copy( + isSmallTablet = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + // This bubble will have max height which is always top aligned on small tablets + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(positioner.getExpandedViewYTopAligned()) + } + + @Test + fun testExpandedViewY_largeScreenLandscape() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + isLandscape = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + // This bubble will have max height which is always top aligned on landscape, large tablet + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(positioner.getExpandedViewYTopAligned()) + } + + @Test + fun testExpandedViewY_largeScreenPortrait() { + val deviceConfig = + defaultDeviceConfig.copy( + isLargeScreen = true, + insets = Insets.of(10, 20, 5, 15), + windowBounds = Rect(0, 0, 1800, 2600) + ) + positioner.update(deviceConfig) + + val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName) + val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor()) + + val manageButtonHeight = + context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height) + val manageButtonPlusMargin = + manageButtonHeight + + 2 * context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_margin) + val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width) + + val expectedExpandedViewY = + positioner.availableRect.bottom - + manageButtonPlusMargin - + positioner.getExpandedViewHeightForLargeScreen() - + pointerWidth + + // Bubbles are bottom aligned on portrait, large tablet + assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) + .isEqualTo(expectedExpandedViewY) + } + + private val defaultYPosition: Float + /** + * Calculates the Y position bubbles should be placed based on the config. Based on the + * calculations in [BubblePositioner.getDefaultStartPosition] and + * [BubbleStackView.RelativeStackPosition]. + */ + get() { + val isTablet = positioner.isLargeScreen + + // On tablet the position is centered, on phone it is an offset from the top. + val desiredY = + if (isTablet) { + positioner.screenRect.height() / 2f - positioner.bubbleSize / 2f + } else { + context.resources + .getDimensionPixelOffset(R.dimen.bubble_stack_starting_offset_y) + .toFloat() + } + // Since we're visually centering the bubbles on tablet, use total screen height rather + // than the available height. + val height = + if (isTablet) { + positioner.screenRect.height() + } else { + positioner.availableRect.height() + } + val offsetPercent = (desiredY / height).coerceIn(0f, 1f) + val allowableStackRegion = + positioner.getAllowableStackPositionRegion(1 /* bubbleCount */) + return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent + } +} diff --git a/libs/WindowManager/Shell/multivalentTestsForDevice b/libs/WindowManager/Shell/multivalentTestsForDevice new file mode 120000 index 000000000000..20ee34ada103 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTestsForDevice @@ -0,0 +1 @@ +multivalentTests
\ No newline at end of file diff --git a/libs/WindowManager/Shell/multivalentTestsForDeviceless b/libs/WindowManager/Shell/multivalentTestsForDeviceless new file mode 120000 index 000000000000..20ee34ada103 --- /dev/null +++ b/libs/WindowManager/Shell/multivalentTestsForDeviceless @@ -0,0 +1 @@ +multivalentTests
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java index 06210ff98642..44ee5615ac74 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java @@ -331,7 +331,9 @@ class ActivityEmbeddingAnimationRunner { if (!animation.hasExtension()) { continue; } - if (adapter.mChange.hasFlags(FLAG_TRANSLUCENT)) { + if (adapter.mChange.hasFlags(FLAG_TRANSLUCENT) + && adapter.mChange.getActivityComponent() != null) { + // Skip edge extension for translucent activity. continue; } final TransitionInfo.Change change = adapter.mChange; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java index 81d963877e4c..bb433dbbd2ce 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java @@ -176,6 +176,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private StatusBarCustomizer mCustomizer; private boolean mTrackingLatency; + // Keep previous navigation type before remove mBackNavigationInfo. + @BackNavigationInfo.BackTargetType + private int mPreviousNavigationType; + public BackAnimationController( @NonNull ShellInit shellInit, @NonNull ShellController shellController, @@ -871,6 +875,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mShellBackAnimationRegistry.resetDefaultCrossActivity(); cancelLatencyTracking(); if (mBackNavigationInfo != null) { + mPreviousNavigationType = mBackNavigationInfo.getType(); mBackNavigationInfo.onBackNavigationFinished(triggerBack); mBackNavigationInfo = null; } @@ -983,7 +988,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont mShellExecutor.execute( () -> { if (!mShellBackAnimationRegistry.cancel( - mBackNavigationInfo.getType())) { + mBackNavigationInfo != null + ? mBackNavigationInfo.getType() + : mPreviousNavigationType)) { return; } if (!mBackGestureStarted) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java index 80fc3a867d48..ac2a1c867462 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java @@ -136,6 +136,9 @@ public class CrossTaskBackAnimation extends ShellBackAnimation { mStartTaskRect.set(mClosingTarget.windowConfiguration.getBounds()); mStartTaskRect.offsetTo(0, 0); + // inset bottom in case of pinned taskbar being present + mStartTaskRect.inset(0, 0, 0, mClosingTarget.contentInsets.bottom); + // Draw background. mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(), BACKGROUNDCOLOR, mTransaction); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 896bcaf98599..e23e15f95640 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -1249,6 +1249,7 @@ public class BubbleController implements ConfigurationChangeListener, } String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user); + Log.v(TAG, "showOrHideAppBubble, with key: " + appBubbleKey); PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier()); if (!isResizableActivity(intent, packageManager, appBubbleKey)) return; @@ -1258,18 +1259,22 @@ public class BubbleController implements ConfigurationChangeListener, if (isStackExpanded()) { if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) { // App bubble is expanded, lets collapse + Log.v(TAG, " showOrHideAppBubble, selected bubble is app bubble, collapsing"); collapseStack(); } else { // App bubble is not selected, select it + Log.v(TAG, " showOrHideAppBubble, expanded, selecting existing app bubble"); mBubbleData.setSelectedBubble(existingAppBubble); } } else { // App bubble is not selected, select it & expand + Log.v(TAG, " showOrHideAppBubble, expand and select existing app bubble"); mBubbleData.setSelectedBubble(existingAppBubble); mBubbleData.setExpanded(true); } } else { // App bubble does not exist, lets add and expand it + Log.v(TAG, " showOrHideAppBubble, creating and expanding app bubble"); Bubble b = Bubble.createAppBubble(intent, user, icon, mMainExecutor); b.setShouldAutoExpand(true); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); 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 470a82511481..ca283128891c 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 @@ -1177,14 +1177,17 @@ public class BubbleStackView extends FrameLayout if (mStackAnimationController.isStackOnLeftSide()) { int availableRectOffsetX = mPositioner.getAvailableRect().left - mPositioner.getScreenRect().left; - animate().translationX(-(mBubbleSize + availableRectOffsetX)).start(); + mBubbleContainer + .animate() + .translationX(-(mBubbleSize + availableRectOffsetX)) + .start(); } else { int availableRectOffsetX = mPositioner.getAvailableRect().right - mPositioner.getScreenRect().right; - animate().translationX(mBubbleSize - availableRectOffsetX).start(); + mBubbleContainer.animate().translationX(mBubbleSize - availableRectOffsetX).start(); } } else { - animate().translationX(0).start(); + mBubbleContainer.animate().translationX(0).start(); } }; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index a587bed3fef0..da1ca8d57940 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -16,6 +16,8 @@ package com.android.wm.shell.desktopmode; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import android.animation.Animator; @@ -39,7 +41,6 @@ import android.view.animation.DecelerateInterpolator; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; -import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; @@ -48,100 +49,71 @@ import com.android.wm.shell.common.SyncTransactionQueue; * Animated visual indicator for Desktop Mode windowing transitions. */ public class DesktopModeVisualIndicator { - public static final int INVALID_INDICATOR = -1; - /** Indicates impending transition into desktop mode */ - public static final int TO_DESKTOP_INDICATOR = 1; - /** Indicates impending transition into fullscreen */ - public static final int TO_FULLSCREEN_INDICATOR = 2; - /** Indicates impending transition into split select on the left side */ - public static final int TO_SPLIT_LEFT_INDICATOR = 3; - /** Indicates impending transition into split select on the right side */ - public static final int TO_SPLIT_RIGHT_INDICATOR = 4; + public enum IndicatorType { + /** To be used when we don't want to indicate any transition */ + NO_INDICATOR, + /** Indicates impending transition into desktop mode */ + TO_DESKTOP_INDICATOR, + /** Indicates impending transition into fullscreen */ + TO_FULLSCREEN_INDICATOR, + /** Indicates impending transition into split select on the left side */ + TO_SPLIT_LEFT_INDICATOR, + /** Indicates impending transition into split select on the right side */ + TO_SPLIT_RIGHT_INDICATOR + } private final Context mContext; private final DisplayController mDisplayController; - private final ShellTaskOrganizer mTaskOrganizer; private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; private final ActivityManager.RunningTaskInfo mTaskInfo; private final SurfaceControl mTaskSurface; - private final Rect mIndicatorRange = new Rect(); private SurfaceControl mLeash; private final SyncTransactionQueue mSyncQueue; private SurfaceControlViewHost mViewHost; private View mView; - private boolean mIsFullscreen; - private int mType; + private IndicatorType mCurrentType; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, - Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer, - RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, int type) { + Context context, SurfaceControl taskSurface, + RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) { mSyncQueue = syncQueue; mTaskInfo = taskInfo; mDisplayController = displayController; mContext = context; mTaskSurface = taskSurface; - mTaskOrganizer = taskOrganizer; mRootTdaOrganizer = taskDisplayAreaOrganizer; - mType = type; - defineIndicatorRange(); + mCurrentType = IndicatorType.NO_INDICATOR; createView(); } /** - * If an indicator is warranted based on the input and task bounds, return the type of - * indicator that should be created. - */ - public static int determineIndicatorType(PointF inputCoordinates, Rect taskBounds, - DisplayLayout layout, Context context) { - int transitionAreaHeight = context.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); - int transitionAreaWidth = context.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); - if (taskBounds.top <= transitionAreaHeight) return TO_FULLSCREEN_INDICATOR; - if (inputCoordinates.x <= transitionAreaWidth) return TO_SPLIT_LEFT_INDICATOR; - if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { - return TO_SPLIT_RIGHT_INDICATOR; - } - return INVALID_INDICATOR; - } - - /** - * Determine range of inputs that will keep this indicator displaying. + * Based on the coordinates of the current drag event, determine which indicator type we should + * display, including no visible indicator. + * TODO(b/280828642): Update drag zones per starting windowing mode. */ - private void defineIndicatorRange() { - DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); - int captionHeight = mContext.getResources().getDimensionPixelSize( - com.android.wm.shell.R.dimen.freeform_decor_caption_height); + IndicatorType updateIndicatorType(PointF inputCoordinates) { + final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); + // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. + IndicatorType result = mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + ? IndicatorType.NO_INDICATOR : IndicatorType.TO_DESKTOP_INDICATOR; int transitionAreaHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); int transitionAreaWidth = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); - switch (mType) { - case TO_DESKTOP_INDICATOR: - // TO_DESKTOP indicator is only dismissed on release; entire display is valid. - mIndicatorRange.set(0, 0, layout.width(), layout.height()); - break; - case TO_FULLSCREEN_INDICATOR: - // If drag results in caption going above the top edge of the display, we still - // want to transition to fullscreen. - mIndicatorRange.set(0, -captionHeight, layout.width(), transitionAreaHeight); - break; - case TO_SPLIT_LEFT_INDICATOR: - mIndicatorRange.set(0, transitionAreaHeight, transitionAreaWidth, layout.height()); - break; - case TO_SPLIT_RIGHT_INDICATOR: - mIndicatorRange.set(layout.width() - transitionAreaWidth, transitionAreaHeight, - layout.width(), layout.height()); - break; - default: - break; + if (inputCoordinates.y <= transitionAreaHeight) { + result = IndicatorType.TO_FULLSCREEN_INDICATOR; + } else if (inputCoordinates.x <= transitionAreaWidth) { + result = IndicatorType.TO_SPLIT_LEFT_INDICATOR; + } else if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { + result = IndicatorType.TO_SPLIT_RIGHT_INDICATOR; } + transitionIndicator(result); + return result; } - /** * Create a fullscreen indicator with no animation */ @@ -156,7 +128,7 @@ public class DesktopModeVisualIndicator { final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); String description; - switch (mType) { + switch (mCurrentType) { case TO_DESKTOP_INDICATOR: description = "Desktop indicator"; break; @@ -201,46 +173,45 @@ public class DesktopModeVisualIndicator { } /** - * Create an indicator. Animator fades it in while expanding the bounds outwards. + * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. */ - public void createIndicatorWithAnimatedBounds() { - mIsFullscreen = mType == TO_FULLSCREEN_INDICATOR; + private void fadeInIndicator(IndicatorType type) { mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator - .animateBounds(mView, mType, + .fadeBoundsIn(mView, type, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); + mCurrentType = type; } /** - * Takes existing fullscreen indicator and animates it to freeform bounds + * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds. */ - public void transitionFullscreenIndicatorToFreeform() { - mIsFullscreen = false; - mType = TO_DESKTOP_INDICATOR; - final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator( - mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); + private void fadeOutIndicator() { + final VisualIndicatorAnimator animator = VisualIndicatorAnimator + .fadeBoundsOut(mView, mCurrentType, + mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); - } + mCurrentType = IndicatorType.NO_INDICATOR; - /** - * Takes the existing freeform indicator and animates it to fullscreen - */ - public void transitionFreeformIndicatorToFullscreen() { - mIsFullscreen = true; - mType = TO_FULLSCREEN_INDICATOR; - final VisualIndicatorAnimator animator = - VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds( - mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); - animator.start(); } /** - * Determine if a MotionEvent is in the same range that enabled the indicator. - * Used to dismiss the indicator when a transition will no longer result from releasing. + * Takes existing indicator and animates it to bounds reflecting a new indicator type. */ - public boolean eventOutsideRange(float x, float y) { - return !mIndicatorRange.contains((int) x, (int) y); + private void transitionIndicator(IndicatorType newType) { + if (mCurrentType == newType) return; + if (mCurrentType == IndicatorType.NO_INDICATOR) { + fadeInIndicator(newType); + } else if (newType == IndicatorType.NO_INDICATOR) { + fadeOutIndicator(); + } else { + final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType( + mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, + newType); + mCurrentType = newType; + animator.start(); + } } /** @@ -260,13 +231,6 @@ public class DesktopModeVisualIndicator { } /** - * Returns true if visual indicator is fullscreen - */ - public boolean isFullscreen() { - return mIsFullscreen; - } - - /** * Animator for Desktop Mode transitions which supports bounds and alpha animation. */ private static class VisualIndicatorAnimator extends ValueAnimator { @@ -274,6 +238,13 @@ public class DesktopModeVisualIndicator { private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float INDICATOR_FINAL_OPACITY = 0.7f; + /** Determines how this animator will interact with the view's alpha: + * Fade in, fade out, or no change to alpha + */ + private enum AlphaAnimType{ + ALPHA_FADE_IN_ANIM, ALPHA_FADE_OUT_ANIM, ALPHA_NO_CHANGE_ANIM + } + private final View mView; private final Rect mStartBounds; private final Rect mEndBounds; @@ -288,87 +259,91 @@ public class DesktopModeVisualIndicator { mRectEvaluator = new RectEvaluator(new Rect()); } - /** - * Create animator for visual indicator of fullscreen transition - * - * @param view the view for this indicator - * @param displayLayout information about the display the transitioning task is currently on - */ - public static VisualIndicatorAnimator toFullscreenAnimatorWithAnimatedBounds( - @NonNull View view, @NonNull DisplayLayout displayLayout) { - final int padding = displayLayout.stableInsets().top; - Rect startBounds = new Rect(padding, padding, - displayLayout.width() - padding, displayLayout.height() - padding); + private static VisualIndicatorAnimator fadeBoundsIn( + @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { + final Rect startBounds = getIndicatorBounds(displayLayout, type); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(startBounds)); animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator); + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM); return animator; } - public static VisualIndicatorAnimator animateBounds( - @NonNull View view, int type, @NonNull DisplayLayout displayLayout) { - final int padding = displayLayout.stableInsets().top; - Rect startBounds = new Rect(); - switch (type) { - case TO_FULLSCREEN_INDICATOR: - startBounds.set(padding, padding, - displayLayout.width() - padding, - displayLayout.height() - padding); - break; - case TO_SPLIT_LEFT_INDICATOR: - startBounds.set(padding, padding, - displayLayout.width() / 2 - padding, - displayLayout.height() - padding); - break; - case TO_SPLIT_RIGHT_INDICATOR: - startBounds.set(displayLayout.width() / 2 + padding, padding, - displayLayout.width() - padding, - displayLayout.height() - padding); - break; - } + private static VisualIndicatorAnimator fadeBoundsOut( + @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { + final Rect endBounds = getIndicatorBounds(displayLayout, type); + final Rect startBounds = getMaxBounds(endBounds); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( - view, startBounds, getMaxBounds(startBounds)); + view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator); + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM); return animator; } /** - * Create animator for visual indicator of freeform transition + * Create animator for visual indicator changing type (i.e., fullscreen to freeform, + * freeform to split, etc.) * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on + * @param origType the original indicator type + * @param newType the new indicator type */ - public static VisualIndicatorAnimator toFreeformAnimator(@NonNull View view, - @NonNull DisplayLayout displayLayout) { - final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; - final int width = displayLayout.width(); - final int height = displayLayout.height(); - Rect startBounds = new Rect(0, 0, width, height); - Rect endBounds = new Rect((int) (adjustmentPercentage * width / 2), - (int) (adjustmentPercentage * height / 2), - (int) (displayLayout.width() - (adjustmentPercentage * width / 2)), - (int) (displayLayout.height() - (adjustmentPercentage * height / 2))); + private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view, + @NonNull DisplayLayout displayLayout, IndicatorType origType, + IndicatorType newType) { + final Rect startBounds = getIndicatorBounds(displayLayout, origType); + final Rect endBounds = getIndicatorBounds(displayLayout, newType); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); - setupIndicatorAnimation(animator); + setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM); return animator; } + private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type) { + final int padding = layout.stableInsets().top; + switch (type) { + case TO_FULLSCREEN_INDICATOR: + return new Rect(padding, padding, + layout.width() - padding, + layout.height() - padding); + case TO_DESKTOP_INDICATOR: + final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; + return new Rect((int) (adjustmentPercentage * layout.width() / 2), + (int) (adjustmentPercentage * layout.height() / 2), + (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)), + (int) (layout.height() - (adjustmentPercentage * layout.height() / 2))); + case TO_SPLIT_LEFT_INDICATOR: + return new Rect(padding, padding, + layout.width() / 2 - padding, + layout.height() - padding); + case TO_SPLIT_RIGHT_INDICATOR: + return new Rect(layout.width() / 2 + padding, padding, + layout.width() - padding, + layout.height() - padding); + default: + throw new IllegalArgumentException("Invalid indicator type provided."); + } + } + /** * Add necessary listener for animation of indicator */ - private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator) { + private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator, + AlphaAnimType animType) { animator.addUpdateListener(a -> { if (animator.mView != null) { animator.updateBounds(a.getAnimatedFraction(), animator.mView); - animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView); + if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) { + animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView); + } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) { + animator.updateIndicatorAlpha(1 - a.getAnimatedFraction(), animator.mView); + } } else { animator.cancel(); } @@ -394,7 +369,7 @@ public class DesktopModeVisualIndicator { if (mStartBounds.equals(mEndBounds)) { return; } - Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); + final Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); view.getBackground().setBounds(currentBounds); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index b1c43c19366d..4f5c39a60120 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -57,7 +57,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener -import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.recents.RecentsTransitionHandler @@ -871,31 +870,34 @@ class DesktopTasksController( * * @param taskInfo the task being dragged. * @param taskSurface SurfaceControl of dragged task. - * @param inputCoordinate coordinates of input. Used for checks against left/right edge of screen. + * @param inputX x coordinate of input. Used for checks against left/right edge of screen. * @param taskBounds bounds of dragged task. Used for checks against status bar height. */ fun onDragPositioningMove( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, - inputCoordinate: PointF, + inputX: Float, taskBounds: Rect ) { - val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return - var type = DesktopModeVisualIndicator.determineIndicatorType(inputCoordinate, - taskBounds, displayLayout, context) - if (type != DesktopModeVisualIndicator.INVALID_INDICATOR && visualIndicator == null) { + updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat()) + } + + fun updateVisualIndicator( + taskInfo: RunningTaskInfo, + taskSurface: SurfaceControl, + inputX: Float, + taskTop: Float + ) { + // If the visual indicator does not exist, create it. + if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator( - syncQueue, taskInfo, - displayController, context, taskSurface, shellTaskOrganizer, - rootTaskDisplayAreaOrganizer, type) - visualIndicator?.createIndicatorWithAnimatedBounds() - return - } - if (visualIndicator?.eventOutsideRange(inputCoordinate.x, - taskBounds.top.toFloat()) == true) { - releaseVisualIndicator() + syncQueue, taskInfo, displayController, context, taskSurface, + rootTaskDisplayAreaOrganizer) } + // Then, update the indicator type. + val indicator = visualIndicator ?: return + indicator.updateIndicatorType(PointF(inputX, taskTop)) } /** @@ -936,45 +938,6 @@ class DesktopTasksController( } /** - * Perform checks required on drag move. Create/release fullscreen indicator and transitions - * indicator to freeform or fullscreen dimensions as needed. - * - * @param taskInfo the task being dragged. - * @param taskSurface SurfaceControl of dragged task. - * @param y coordinate of dragged task. Used for checks against status bar height. - */ - fun onDragPositioningMoveThroughStatusBar( - taskInfo: RunningTaskInfo, - taskSurface: SurfaceControl, - y: Float - ) { - // If the motion event is above the status bar and the visual indicator is not yet visible, - // return since we do not need to show the visual indicator at this point. - if (y < getStatusBarHeight(taskInfo) && visualIndicator == null) { - return - } - if (visualIndicator == null) { - visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, - displayController, context, taskSurface, shellTaskOrganizer, - rootTaskDisplayAreaOrganizer, TO_DESKTOP_INDICATOR) - // TODO(b/301106941): don't show the indicator until the drag-to-desktop animation has - // started, or it'll be visible too early on top of the task surface, especially in - // the cancel-early case. Also because it shouldn't even be shown in the cancel-early - // case since its dismissal is tied to the cancel animation end, which doesn't even run - // in cancel-early. - visualIndicator?.createIndicatorWithAnimatedBounds() - } - val indicator = visualIndicator ?: return - if (y >= getFreeformTransitionStatusBarDragThreshold(taskInfo)) { - if (indicator.isFullscreen) { - indicator.transitionFullscreenIndicatorToFreeform() - } - } else if (!indicator.isFullscreen) { - indicator.transitionFreeformIndicatorToFullscreen() - } - } - - /** * Perform checks required when drag ends under status bar area. * * @param taskInfo the task being dragged. @@ -992,14 +955,6 @@ class DesktopTasksController( } /** - * Returns the threshold at which we transition a task into freeform when dragging a - * fullscreen task down from the status bar - */ - private fun getFreeformTransitionStatusBarDragThreshold(taskInfo: RunningTaskInfo): Int { - return 2 * getStatusBarHeight(taskInfo) - } - - /** * Update the exclusion region for a specified task */ fun onExclusionRegionChanged(taskId: Int, exclusionRegion: Region) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index 89dcc4c1d261..8e375a9ef5ee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -987,10 +987,12 @@ public class PipTransition extends PipTransitionController { 0 /* startingAngle */, rotationDelta); if (sourceHintRect == null) { // We use content overlay when there is no source rect hint to enter PiP use bounds - // animation. + // animation. We also temporarily disallow app icon overlay and use color overlay + // instead when in fixed rotation enter PiP in button nav with no sourceRectHint. + // TODO(b/319286295): Fix App Icon Overlay animation in fixed rotation in btn nav. // TODO(b/272819817): cleanup the null-check and extra logging. final boolean hasTopActivityInfo = taskInfo.topActivityInfo != null; - if (hasTopActivityInfo) { + if (hasTopActivityInfo && mFixedRotationState != FIXED_ROTATION_TRANSITION) { animator.setAppIconContentOverlay( mContext, currentBounds, destinationBounds, taskInfo.topActivityInfo, mPipBoundsState.getLauncherState().getAppIconSizePx()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java index bc1a57572c63..5de8a9be9576 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java @@ -481,18 +481,20 @@ class SplitScreenTransitions { private void startFadeAnimation(@NonNull SurfaceControl leash, boolean show) { final float end = show ? 1.f : 0.f; final float start = 1.f - end; - final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); final ValueAnimator va = ValueAnimator.ofFloat(start, end); va.setDuration(FADE_DURATION); va.setInterpolator(show ? ALPHA_IN : ALPHA_OUT); va.addUpdateListener(animation -> { float fraction = animation.getAnimatedFraction(); + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction); transaction.apply(); + mTransactionPool.release(transaction); }); va.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { + final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); transaction.setAlpha(leash, end); transaction.apply(); mTransactionPool.release(transaction); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java index 0eb7c2d98e0a..a7843e218a8a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java @@ -293,11 +293,7 @@ public class ShellController { private class ShellInterfaceImpl implements ShellInterface { @Override public void onInit() { - try { - mMainExecutor.executeBlocking(() -> ShellController.this.handleInit()); - } catch (InterruptedException e) { - throw new RuntimeException("Failed to initialize the Shell in 2s", e); - } + mMainExecutor.execute(ShellController.this::handleInit); } @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java index db845137540b..bf783e6af36f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java @@ -124,6 +124,16 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, int mAnimType = ANIM_TYPE_DEFAULT; final IBinder mTransition; + private final Transitions mPlayer; + private final DefaultMixedHandler mMixedHandler; + private final PipTransitionController mPipHandler; + private final RecentsTransitionHandler mRecentsHandler; + private final StageCoordinator mSplitHandler; + private final KeyguardTransitionHandler mKeyguardHandler; + private final DesktopTasksController mDesktopTasksController; + private final UnfoldTransitionHandler mUnfoldHandler; + private final ActivityEmbeddingController mActivityEmbeddingController; + Transitions.TransitionHandler mLeftoversHandler = null; TransitionInfo mInfo = null; WindowContainerTransaction mFinishWCT = null; @@ -144,9 +154,408 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, */ int mInFlightSubAnimations = 0; - MixedTransition(int type, IBinder transition) { + MixedTransition(int type, IBinder transition, Transitions player, + DefaultMixedHandler mixedHandler, PipTransitionController pipHandler, + RecentsTransitionHandler recentsHandler, StageCoordinator splitHandler, + KeyguardTransitionHandler keyguardHandler, + DesktopTasksController desktopTasksController, + UnfoldTransitionHandler unfoldHandler, + ActivityEmbeddingController activityEmbeddingController) { mType = type; mTransition = transition; + mPlayer = player; + mMixedHandler = mixedHandler; + mPipHandler = pipHandler; + mRecentsHandler = recentsHandler; + mSplitHandler = splitHandler; + mKeyguardHandler = keyguardHandler; + mDesktopTasksController = desktopTasksController; + mUnfoldHandler = unfoldHandler; + mActivityEmbeddingController = activityEmbeddingController; + + switch (type) { + case TYPE_RECENTS_DURING_DESKTOP: + case TYPE_RECENTS_DURING_KEYGUARD: + case TYPE_RECENTS_DURING_SPLIT: + mLeftoversHandler = mRecentsHandler; + break; + case TYPE_UNFOLD: + mLeftoversHandler = mUnfoldHandler; + break; + case TYPE_DISPLAY_AND_SPLIT_CHANGE: + case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: + case TYPE_ENTER_PIP_FROM_SPLIT: + case TYPE_KEYGUARD: + case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE: + default: + break; + } + } + + boolean startAnimation( + @NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + switch (mType) { + case TYPE_ENTER_PIP_FROM_SPLIT: + return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction, + finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler); + case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: + return animateEnterPipFromActivityEmbedding( + info, startTransaction, finishTransaction, finishCallback); + case TYPE_DISPLAY_AND_SPLIT_CHANGE: + return false; + case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE: + final boolean handledToPip = animateOpenIntentWithRemoteAndPip( + info, startTransaction, finishTransaction, finishCallback); + // Consume the transition on remote handler if the leftover handler already + // handle this transition. And if it cannot, the transition will be handled by + // remote handler, so don't consume here. + // Need to check leftOverHandler as it may change in + // #animateOpenIntentWithRemoteAndPip + if (handledToPip && mHasRequestToRemote + && mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) { + mPlayer.getRemoteTransitionHandler().onTransitionConsumed( + transition, false, null); + } + return handledToPip; + case TYPE_RECENTS_DURING_SPLIT: + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + // Pip auto-entering info might be appended to recent transition like + // pressing home-key in 3-button navigation. This offers split handler the + // opportunity to handle split to pip animation. + if (mPipHandler.isEnteringPip(change, info.getType()) + && mSplitHandler.getSplitItemPosition(change.getLastParent()) + != SPLIT_POSITION_UNDEFINED) { + return animateEnterPipFromSplit( + this, info, startTransaction, finishTransaction, finishCallback, + mPlayer, mMixedHandler, mPipHandler, mSplitHandler); + } + } + + return animateRecentsDuringSplit( + info, startTransaction, finishTransaction, finishCallback); + case TYPE_KEYGUARD: + return animateKeyguard(this, info, startTransaction, finishTransaction, + finishCallback, mKeyguardHandler, mPipHandler); + case TYPE_RECENTS_DURING_KEYGUARD: + return animateRecentsDuringKeyguard( + info, startTransaction, finishTransaction, finishCallback); + case TYPE_RECENTS_DURING_DESKTOP: + return animateRecentsDuringDesktop( + info, startTransaction, finishTransaction, finishCallback); + case TYPE_UNFOLD: + return animateUnfold( + info, startTransaction, finishTransaction, finishCallback); + default: + throw new IllegalStateException( + "Starting mixed animation without a known mixed type? " + mType); + } + } + + private boolean animateEnterPipFromActivityEmbedding( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for " + + "entering PIP from an Activity Embedding window"); + // Split into two transitions (wct) + TransitionInfo.Change pipChange = null; + final TransitionInfo everythingElse = + subCopy(info, TRANSIT_TO_BACK, true /* changes */); + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + TransitionInfo.Change change = info.getChanges().get(i); + if (mPipHandler.isEnteringPip(change, info.getType())) { + if (pipChange != null) { + throw new IllegalStateException("More than 1 pip-entering changes in one" + + " transition? " + info); + } + pipChange = change; + // going backwards, so remove-by-index is fine. + everythingElse.getChanges().remove(i); + } + } + + final Transitions.TransitionFinishCallback finishCB = (wct) -> { + --mInFlightSubAnimations; + joinFinishArgs(wct); + if (mInFlightSubAnimations > 0) return; + finishCallback.onTransitionFinished(mFinishWCT); + }; + + if (!mActivityEmbeddingController.shouldAnimate(everythingElse)) { + // Fallback to dispatching to other handlers. + return false; + } + + // PIP window should always be on the highest Z order. + if (pipChange != null) { + mInFlightSubAnimations = 2; + mPipHandler.startEnterAnimation( + pipChange, + startTransaction.setLayer(pipChange.getLeash(), Integer.MAX_VALUE), + finishTransaction, + finishCB); + } else { + mInFlightSubAnimations = 1; + } + + mActivityEmbeddingController.startAnimation(mTransition, everythingElse, + startTransaction, finishTransaction, finishCB); + return true; + } + + private boolean animateOpenIntentWithRemoteAndPip( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + TransitionInfo.Change pipChange = null; + for (int i = info.getChanges().size() - 1; i >= 0; --i) { + TransitionInfo.Change change = info.getChanges().get(i); + if (mPipHandler.isEnteringPip(change, info.getType())) { + if (pipChange != null) { + throw new IllegalStateException("More than 1 pip-entering changes in one" + + " transition? " + info); + } + pipChange = change; + info.getChanges().remove(i); + } + } + Transitions.TransitionFinishCallback finishCB = (wct) -> { + --mInFlightSubAnimations; + joinFinishArgs(wct); + if (mInFlightSubAnimations > 0) return; + finishCallback.onTransitionFinished(mFinishWCT); + }; + if (pipChange == null) { + if (mLeftoversHandler != null) { + mInFlightSubAnimations = 1; + if (mLeftoversHandler.startAnimation( + mTransition, info, startTransaction, finishTransaction, finishCB)) { + return true; + } + } + return false; + } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Splitting PIP into a separate" + + " animation because remote-animation likely doesn't support it"); + // Split the transition into 2 parts: the pip part and the rest. + mInFlightSubAnimations = 2; + // make a new startTransaction because pip's startEnterAnimation "consumes" it so + // we need a separate one to send over to launcher. + SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction(); + + mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, finishCB); + + // Dispatch the rest of the transition normally. + if (mLeftoversHandler != null + && mLeftoversHandler.startAnimation( + mTransition, info, startTransaction, finishTransaction, finishCB)) { + return true; + } + mLeftoversHandler = mPlayer.dispatchTransition(mTransition, info, + startTransaction, finishTransaction, finishCB, mMixedHandler); + return true; + } + + private boolean animateRecentsDuringSplit( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + // Split-screen is only interested in the recents transition finishing (and merging), so + // just wrap finish and start recents animation directly. + Transitions.TransitionFinishCallback finishCB = (wct) -> { + mInFlightSubAnimations = 0; + // If pair-to-pair switching, the post-recents clean-up isn't needed. + wct = wct != null ? wct : new WindowContainerTransaction(); + if (mAnimType != ANIM_TYPE_PAIR_TO_PAIR) { + mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction); + } else { + // notify pair-to-pair recents animation finish + mSplitHandler.onRecentsPairToPairAnimationFinish(wct); + } + mSplitHandler.onTransitionAnimationComplete(); + finishCallback.onTransitionFinished(wct); + }; + mInFlightSubAnimations = 1; + mSplitHandler.onRecentsInSplitAnimationStart(info); + final boolean handled = mLeftoversHandler.startAnimation(mTransition, info, + startTransaction, finishTransaction, finishCB); + if (!handled) { + mSplitHandler.onRecentsInSplitAnimationCanceled(); + } + return handled; + } + + private boolean animateRecentsDuringKeyguard( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + if (mInfo == null) { + mInfo = info; + mFinishT = finishTransaction; + mFinishCB = finishCallback; + } + return startSubAnimation(mRecentsHandler, info, startTransaction, finishTransaction); + } + + private boolean animateRecentsDuringDesktop( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + Transitions.TransitionFinishCallback finishCB = wct -> { + mInFlightSubAnimations--; + if (mInFlightSubAnimations == 0) { + finishCallback.onTransitionFinished(wct); + } + }; + + mInFlightSubAnimations++; + boolean consumed = mRecentsHandler.startAnimation( + mTransition, info, startTransaction, finishTransaction, finishCB); + if (!consumed) { + mInFlightSubAnimations--; + return false; + } + if (mDesktopTasksController != null) { + mDesktopTasksController.syncSurfaceState(info, finishTransaction); + return true; + } + + return false; + } + + private boolean animateUnfold( + @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction startTransaction, + @NonNull SurfaceControl.Transaction finishTransaction, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + final Transitions.TransitionFinishCallback finishCB = (wct) -> { + mInFlightSubAnimations--; + if (mInFlightSubAnimations > 0) return; + finishCallback.onTransitionFinished(wct); + }; + mInFlightSubAnimations = 1; + // Sync pip state. + if (mPipHandler != null) { + mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction); + } + if (mSplitHandler != null && mSplitHandler.isSplitActive()) { + mSplitHandler.updateSurfaces(startTransaction); + } + return mUnfoldHandler.startAnimation( + mTransition, info, startTransaction, finishTransaction, finishCB); + } + + void mergeAnimation( + @NonNull IBinder transition, @NonNull TransitionInfo info, + @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget, + @NonNull Transitions.TransitionFinishCallback finishCallback) { + switch (mType) { + case TYPE_DISPLAY_AND_SPLIT_CHANGE: + // queue since no actual animation. + break; + case TYPE_ENTER_PIP_FROM_SPLIT: + if (mAnimType == ANIM_TYPE_GOING_HOME) { + boolean ended = mSplitHandler.end(); + // If split couldn't end (because it is remote), then don't end everything + // else since we have to play out the animation anyways. + if (!ended) return; + mPipHandler.end(); + if (mLeftoversHandler != null) { + mLeftoversHandler.mergeAnimation( + transition, info, t, mergeTarget, finishCallback); + } + } else { + mPipHandler.end(); + } + break; + case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: + mPipHandler.end(); + mActivityEmbeddingController.mergeAnimation(transition, info, t, mergeTarget, + finishCallback); + break; + case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE: + mPipHandler.end(); + if (mLeftoversHandler != null) { + mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, + finishCallback); + } + break; + case TYPE_RECENTS_DURING_SPLIT: + if (mSplitHandler.isPendingEnter(transition)) { + // Recents -> enter-split means that we are switching from one pair to + // another pair. + mAnimType = ANIM_TYPE_PAIR_TO_PAIR; + } + mLeftoversHandler.mergeAnimation( + transition, info, t, mergeTarget, finishCallback); + break; + case TYPE_KEYGUARD: + mKeyguardHandler.mergeAnimation( + transition, info, t, mergeTarget, finishCallback); + break; + case TYPE_RECENTS_DURING_KEYGUARD: + if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) { + DefaultMixedHandler.handoverTransitionLeashes(mInfo, info, t, mFinishT); + if (animateKeyguard(this, info, t, mFinishT, mFinishCB, mKeyguardHandler, + mPipHandler)) { + finishCallback.onTransitionFinished(null); + } + } + mLeftoversHandler.mergeAnimation( + transition, info, t, mergeTarget, finishCallback); + break; + case TYPE_RECENTS_DURING_DESKTOP: + mLeftoversHandler.mergeAnimation( + transition, info, t, mergeTarget, finishCallback); + break; + case TYPE_UNFOLD: + mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); + break; + default: + throw new IllegalStateException( + "Playing a mixed transition with unknown type? " + mType); + } + } + + void onTransitionConsumed( + @NonNull IBinder transition, boolean aborted, + @Nullable SurfaceControl.Transaction finishT) { + switch (mType) { + case TYPE_ENTER_PIP_FROM_SPLIT: + mPipHandler.onTransitionConsumed(transition, aborted, finishT); + break; + case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING: + mPipHandler.onTransitionConsumed(transition, aborted, finishT); + mActivityEmbeddingController.onTransitionConsumed(transition, aborted, finishT); + break; + case TYPE_RECENTS_DURING_SPLIT: + case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE: + case TYPE_RECENTS_DURING_DESKTOP: + mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); + break; + case TYPE_KEYGUARD: + mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT); + break; + case TYPE_UNFOLD: + mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT); + break; + default: + break; + } + + if (mHasRequestToRemote) { + mPlayer.getRemoteTransitionHandler().onTransitionConsumed( + transition, aborted, finishT); + } } boolean startSubAnimation(Transitions.TransitionHandler handler, TransitionInfo info, @@ -235,8 +644,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, throw new IllegalStateException("Unexpected remote transition in" + "pip-enter-from-split request"); } - mActiveTransitions.add(new MixedTransition(MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, - transition)); + mActiveTransitions.add(createMixedTransition( + MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition)); WindowContainerTransaction out = new WindowContainerTransaction(); mPipHandler.augmentRequest(transition, request, out); @@ -247,7 +656,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, mActivityEmbeddingController != null)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a PiP-enter request from an Activity Embedding split"); - mActiveTransitions.add(new MixedTransition( + mActiveTransitions.add(createMixedTransition( MixedTransition.TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING, transition)); // Postpone transition splitting to later. WindowContainerTransaction out = new WindowContainerTransaction(); @@ -266,7 +675,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, if (handler == null) { return null; } - final MixedTransition mixed = new MixedTransition( + final MixedTransition mixed = createMixedTransition( MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE, transition); mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); @@ -292,7 +701,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, mPlayer.getRemoteTransitionHandler(), new WindowContainerTransaction()); } - final MixedTransition mixed = new MixedTransition( + final MixedTransition mixed = createMixedTransition( MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition); mixed.mLeftoversHandler = handler.first; mActiveTransitions.add(mixed); @@ -301,10 +710,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, final WindowContainerTransaction wct = mUnfoldHandler.handleRequest(transition, request); if (wct != null) { - final MixedTransition mixed = new MixedTransition( - MixedTransition.TYPE_UNFOLD, transition); - mixed.mLeftoversHandler = mUnfoldHandler; - mActiveTransitions.add(mixed); + mActiveTransitions.add(createMixedTransition( + MixedTransition.TYPE_UNFOLD, transition)); } return wct; } @@ -330,31 +737,31 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, private void setRecentsTransitionDuringSplit(IBinder transition) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "Split-Screen is foreground, so treat it as Mixed."); - final MixedTransition mixed = new MixedTransition( - MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition); - mixed.mLeftoversHandler = mRecentsHandler; - mActiveTransitions.add(mixed); + mActiveTransitions.add(createMixedTransition( + MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition)); } private void setRecentsTransitionDuringKeyguard(IBinder transition) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "keyguard is visible, so treat it as Mixed."); - final MixedTransition mixed = new MixedTransition( - MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition); - mixed.mLeftoversHandler = mRecentsHandler; - mActiveTransitions.add(mixed); + mActiveTransitions.add(createMixedTransition( + MixedTransition.TYPE_RECENTS_DURING_KEYGUARD, transition)); } private void setRecentsTransitionDuringDesktop(IBinder transition) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while " + "desktop mode is active, so treat it as Mixed."); - final MixedTransition mixed = new MixedTransition( - MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition); - mixed.mLeftoversHandler = mRecentsHandler; - mActiveTransitions.add(mixed); + mActiveTransitions.add(createMixedTransition( + MixedTransition.TYPE_RECENTS_DURING_DESKTOP, transition)); + } + + private MixedTransition createMixedTransition(int type, IBinder transition) { + return new MixedTransition(type, transition, mPlayer, this, mPipHandler, mRecentsHandler, + mSplitHandler, mKeyguardHandler, mDesktopTasksController, mUnfoldHandler, + mActivityEmbeddingController); } - private TransitionInfo subCopy(@NonNull TransitionInfo info, + private static TransitionInfo subCopy(@NonNull TransitionInfo info, @WindowManager.TransitionType int newType, boolean withChanges) { final TransitionInfo out = new TransitionInfo(newType, withChanges ? info.getFlags() : 0); out.setTrack(info.getTrack()); @@ -371,12 +778,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, return out; } - private boolean isHomeOpening(@NonNull TransitionInfo.Change change) { + private static boolean isHomeOpening(@NonNull TransitionInfo.Change change) { return change.getTaskInfo() != null && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME; } - private boolean isWallpaper(@NonNull TransitionInfo.Change change) { + private static boolean isWallpaper(@NonNull TransitionInfo.Change change) { return (change.getFlags() & FLAG_IS_WALLPAPER) != 0; } @@ -398,14 +805,15 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, if (KeyguardTransitionHandler.handles(info)) { if (mixed != null && mixed.mType != MixedTransition.TYPE_KEYGUARD) { final MixedTransition keyguardMixed = - new MixedTransition(MixedTransition.TYPE_KEYGUARD, transition); + createMixedTransition(MixedTransition.TYPE_KEYGUARD, transition); mActiveTransitions.add(keyguardMixed); Transitions.TransitionFinishCallback callback = wct -> { mActiveTransitions.remove(keyguardMixed); finishCallback.onTransitionFinished(wct); }; final boolean hasAnimateKeyguard = animateKeyguard( - keyguardMixed, info, startTransaction, finishTransaction, callback); + keyguardMixed, info, startTransaction, finishTransaction, callback, + mKeyguardHandler, mPipHandler); if (hasAnimateKeyguard) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Converting mixed transition into a keyguard transition"); @@ -429,175 +837,21 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, finishCallback.onTransitionFinished(wct); }; - if (chosenTransition.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { - return animateEnterPipFromSplit( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType - == MixedTransition.TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) { - return animateEnterPipFromActivityEmbedding( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) { - return false; - } else if (chosenTransition.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { - final boolean handledToPip = animateOpenIntentWithRemoteAndPip( - chosenTransition, info, startTransaction, finishTransaction, callback); - // Consume the transition on remote handler if the leftover handler already handle this - // transition. And if it cannot, the transition will be handled by remote handler, so - // don't consume here. - // Need to check leftOverHandler as it may change in #animateOpenIntentWithRemoteAndPip - if (handledToPip && chosenTransition.mHasRequestToRemote - && chosenTransition.mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) { - mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, false, null); - } - return handledToPip; - } else if (chosenTransition.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - final TransitionInfo.Change change = info.getChanges().get(i); - // Pip auto-entering info might be appended to recent transition like pressing - // home-key in 3-button navigation. This offers split handler the opportunity to - // handle split to pip animation. - if (mPipHandler.isEnteringPip(change, info.getType()) - && mSplitHandler.getSplitItemPosition(change.getLastParent()) - != SPLIT_POSITION_UNDEFINED) { - return animateEnterPipFromSplit( - chosenTransition, info, startTransaction, finishTransaction, callback); - } - } - - return animateRecentsDuringSplit( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType == MixedTransition.TYPE_KEYGUARD) { - return animateKeyguard( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) { - return animateRecentsDuringKeyguard( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { - return animateRecentsDuringDesktop( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else if (chosenTransition.mType == MixedTransition.TYPE_UNFOLD) { - return animateUnfold( - chosenTransition, info, startTransaction, finishTransaction, callback); - } else { + boolean handled = chosenTransition.startAnimation( + transition, info, startTransaction, finishTransaction, callback); + if (!handled) { mActiveTransitions.remove(chosenTransition); - throw new IllegalStateException("Starting mixed animation without a known mixed type? " - + chosenTransition.mType); } + return handled; } - private boolean animateEnterPipFromActivityEmbedding(@NonNull MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for " - + "entering PIP from an Activity Embedding window"); - // Split into two transitions (wct) - TransitionInfo.Change pipChange = null; - final TransitionInfo everythingElse = subCopy(info, TRANSIT_TO_BACK, true /* changes */); - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - TransitionInfo.Change change = info.getChanges().get(i); - if (mPipHandler.isEnteringPip(change, info.getType())) { - if (pipChange != null) { - throw new IllegalStateException("More than 1 pip-entering changes in one" - + " transition? " + info); - } - pipChange = change; - // going backwards, so remove-by-index is fine. - everythingElse.getChanges().remove(i); - } - } - - final Transitions.TransitionFinishCallback finishCB = (wct) -> { - --mixed.mInFlightSubAnimations; - mixed.joinFinishArgs(wct); - if (mixed.mInFlightSubAnimations > 0) return; - mActiveTransitions.remove(mixed); - finishCallback.onTransitionFinished(mixed.mFinishWCT); - }; - - if (!mActivityEmbeddingController.shouldAnimate(everythingElse)) { - // Fallback to dispatching to other handlers. - return false; - } - - // PIP window should always be on the highest Z order. - if (pipChange != null) { - mixed.mInFlightSubAnimations = 2; - mPipHandler.startEnterAnimation( - pipChange, startTransaction.setLayer(pipChange.getLeash(), Integer.MAX_VALUE), - finishTransaction, - finishCB); - } else { - mixed.mInFlightSubAnimations = 1; - } - - mActivityEmbeddingController.startAnimation(mixed.mTransition, everythingElse, - startTransaction, finishTransaction, finishCB); - return true; - } - - private boolean animateOpenIntentWithRemoteAndPip(@NonNull MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - TransitionInfo.Change pipChange = null; - for (int i = info.getChanges().size() - 1; i >= 0; --i) { - TransitionInfo.Change change = info.getChanges().get(i); - if (mPipHandler.isEnteringPip(change, info.getType())) { - if (pipChange != null) { - throw new IllegalStateException("More than 1 pip-entering changes in one" - + " transition? " + info); - } - pipChange = change; - info.getChanges().remove(i); - } - } - Transitions.TransitionFinishCallback finishCB = (wct) -> { - --mixed.mInFlightSubAnimations; - mixed.joinFinishArgs(wct); - if (mixed.mInFlightSubAnimations > 0) return; - mActiveTransitions.remove(mixed); - finishCallback.onTransitionFinished(mixed.mFinishWCT); - }; - if (pipChange == null) { - if (mixed.mLeftoversHandler != null) { - mixed.mInFlightSubAnimations = 1; - if (mixed.mLeftoversHandler.startAnimation(mixed.mTransition, - info, startTransaction, finishTransaction, finishCB)) { - return true; - } - } - mActiveTransitions.remove(mixed); - return false; - } - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Splitting PIP into a separate" - + " animation because remote-animation likely doesn't support it"); - // Split the transition into 2 parts: the pip part and the rest. - mixed.mInFlightSubAnimations = 2; - // make a new startTransaction because pip's startEnterAnimation "consumes" it so - // we need a separate one to send over to launcher. - SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction(); - - mPipHandler.startEnterAnimation(pipChange, otherStartT, finishTransaction, finishCB); - - // Dispatch the rest of the transition normally. - if (mixed.mLeftoversHandler != null - && mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, - startTransaction, finishTransaction, finishCB)) { - return true; - } - mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, info, - startTransaction, finishTransaction, finishCB, this); - return true; - } - - private boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed, + private static boolean animateEnterPipFromSplit(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { + @NonNull Transitions.TransitionFinishCallback finishCallback, + @NonNull Transitions player, @NonNull DefaultMixedHandler mixedHandler, + @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animating a mixed transition for " + "entering PIP while Split-Screen is foreground."); TransitionInfo.Change pipChange = null; @@ -606,7 +860,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, boolean homeIsOpening = false; for (int i = info.getChanges().size() - 1; i >= 0; --i) { TransitionInfo.Change change = info.getChanges().get(i); - if (mPipHandler.isEnteringPip(change, info.getType())) { + if (pipHandler.isEnteringPip(change, info.getType())) { if (pipChange != null) { throw new IllegalStateException("More than 1 pip-entering changes in one" + " transition? " + info); @@ -622,7 +876,6 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, } if (pipChange == null) { // um, something probably went wrong. - mActiveTransitions.remove(mixed); return false; } final boolean isGoingHome = homeIsOpening; @@ -630,13 +883,12 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, --mixed.mInFlightSubAnimations; mixed.joinFinishArgs(wct); if (mixed.mInFlightSubAnimations > 0) return; - mActiveTransitions.remove(mixed); if (isGoingHome) { - mSplitHandler.onTransitionAnimationComplete(); + splitHandler.onTransitionAnimationComplete(); } finishCallback.onTransitionFinished(mixed.mFinishWCT); }; - if (isGoingHome || mSplitHandler.getSplitItemPosition(pipChange.getLastParent()) + if (isGoingHome || splitHandler.getSplitItemPosition(pipChange.getLastParent()) != SPLIT_POSITION_UNDEFINED) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is actually mixed " + "since entering-PiP caused us to leave split and return home."); @@ -652,7 +904,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, // we need a separate one to send over to launcher. SurfaceControl.Transaction otherStartT = new SurfaceControl.Transaction(); @SplitScreen.StageType int topStageToKeep = STAGE_TYPE_UNDEFINED; - if (mSplitHandler.isSplitScreenVisible()) { + if (splitHandler.isSplitScreenVisible()) { // The non-going home case, we could be pip-ing one of the split stages and keep // showing the other for (int i = info.getChanges().size() - 1; i >= 0; --i) { @@ -662,7 +914,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, continue; } @SplitScreen.StageType int splitItemStage = - mSplitHandler.getSplitItemStage(change.getLastParent()); + splitHandler.getSplitItemStage(change.getLastParent()); if (splitItemStage != STAGE_TYPE_UNDEFINED) { topStageToKeep = splitItemStage; break; @@ -670,7 +922,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, } } // Let split update internal state for dismiss. - mSplitHandler.prepareDismissAnimation(topStageToKeep, + splitHandler.prepareDismissAnimation(topStageToKeep, EXIT_REASON_CHILD_TASK_ENTER_PIP, everythingElse, otherStartT, finishTransaction); @@ -684,13 +936,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, } } - mPipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); - mPipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, + pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA); + pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction, finishCB); // Dispatch the rest of the transition normally. This will most-likely be taken by // recents or default handler. - mixed.mLeftoversHandler = mPlayer.dispatchTransition(mixed.mTransition, everythingElse, - otherStartT, finishTransaction, finishCB, this); + mixed.mLeftoversHandler = player.dispatchTransition(mixed.mTransition, everythingElse, + otherStartT, finishTransaction, finishCB, mixedHandler); } else { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Not leaving split, so just " + "forward animation to Pip-Handler."); @@ -698,7 +950,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, // new pip task is spawned). In this case, we don't actually exit split so we can // just let pip transition handle the animation verbatim. mixed.mInFlightSubAnimations = 1; - mPipHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction, + pipHandler.startAnimation(mixed.mTransition, info, startTransaction, finishTransaction, finishCB); } return true; @@ -735,14 +987,15 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, public boolean animatePendingEnterPipFromSplit(IBinder transition, TransitionInfo info, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCallback) { - final MixedTransition mixed = new MixedTransition( + final MixedTransition mixed = createMixedTransition( MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT, transition); mActiveTransitions.add(mixed); Transitions.TransitionFinishCallback callback = wct -> { mActiveTransitions.remove(mixed); finishCallback.onTransitionFinished(wct); }; - return animateEnterPipFromSplit(mixed, info, startT, finishT, callback); + return animateEnterPipFromSplit(mixed, info, startT, finishT, finishCallback, mPlayer, this, + mPipHandler, mSplitHandler); } /** @@ -765,7 +1018,7 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, } if (displayPart.getChanges().isEmpty()) return false; unlinkMissingParents(everythingElse); - final MixedTransition mixed = new MixedTransition( + final MixedTransition mixed = createMixedTransition( MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE, transition); mActiveTransitions.add(mixed); ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Animation is a mix of display change " @@ -794,116 +1047,22 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, return true; } - private boolean animateRecentsDuringSplit(@NonNull final MixedTransition mixed, + private static boolean animateKeyguard(@NonNull final MixedTransition mixed, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - // Split-screen is only interested in the recents transition finishing (and merging), so - // just wrap finish and start recents animation directly. - Transitions.TransitionFinishCallback finishCB = (wct) -> { - mixed.mInFlightSubAnimations = 0; - mActiveTransitions.remove(mixed); - // If pair-to-pair switching, the post-recents clean-up isn't needed. - wct = wct != null ? wct : new WindowContainerTransaction(); - if (mixed.mAnimType != MixedTransition.ANIM_TYPE_PAIR_TO_PAIR) { - mSplitHandler.onRecentsInSplitAnimationFinish(wct, finishTransaction); - } else { - // notify pair-to-pair recents animation finish - mSplitHandler.onRecentsPairToPairAnimationFinish(wct); - } - mSplitHandler.onTransitionAnimationComplete(); - finishCallback.onTransitionFinished(wct); - }; - mixed.mInFlightSubAnimations = 1; - mSplitHandler.onRecentsInSplitAnimationStart(info); - final boolean handled = mixed.mLeftoversHandler.startAnimation(mixed.mTransition, info, - startTransaction, finishTransaction, finishCB); - if (!handled) { - mSplitHandler.onRecentsInSplitAnimationCanceled(); - mActiveTransitions.remove(mixed); - } - return handled; - } - - private boolean animateKeyguard(@NonNull final MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { + @NonNull Transitions.TransitionFinishCallback finishCallback, + @NonNull KeyguardTransitionHandler keyguardHandler, + PipTransitionController pipHandler) { if (mixed.mFinishT == null) { mixed.mFinishT = finishTransaction; mixed.mFinishCB = finishCallback; } // Sync pip state. - if (mPipHandler != null) { - mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction); - } - return mixed.startSubAnimation(mKeyguardHandler, info, startTransaction, finishTransaction); - } - - private boolean animateRecentsDuringKeyguard(@NonNull final MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - if (mixed.mInfo == null) { - mixed.mInfo = info; - mixed.mFinishT = finishTransaction; - mixed.mFinishCB = finishCallback; + if (pipHandler != null) { + pipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction); } - return mixed.startSubAnimation(mRecentsHandler, info, startTransaction, finishTransaction); - } - - private boolean animateRecentsDuringDesktop(@NonNull final MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - Transitions.TransitionFinishCallback finishCB = wct -> { - mixed.mInFlightSubAnimations--; - if (mixed.mInFlightSubAnimations == 0) { - mActiveTransitions.remove(mixed); - finishCallback.onTransitionFinished(wct); - } - }; - - mixed.mInFlightSubAnimations++; - boolean consumed = mRecentsHandler.startAnimation( - mixed.mTransition, info, startTransaction, finishTransaction, finishCB); - if (!consumed) { - mixed.mInFlightSubAnimations--; - return false; - } - if (mDesktopTasksController != null) { - mDesktopTasksController.syncSurfaceState(info, finishTransaction); - return true; - } - - return false; - } - - private boolean animateUnfold(@NonNull final MixedTransition mixed, - @NonNull TransitionInfo info, - @NonNull SurfaceControl.Transaction startTransaction, - @NonNull SurfaceControl.Transaction finishTransaction, - @NonNull Transitions.TransitionFinishCallback finishCallback) { - final Transitions.TransitionFinishCallback finishCB = (wct) -> { - mixed.mInFlightSubAnimations--; - if (mixed.mInFlightSubAnimations > 0) return; - mActiveTransitions.remove(mixed); - finishCallback.onTransitionFinished(wct); - }; - mixed.mInFlightSubAnimations = 1; - // Sync pip state. - if (mPipHandler != null) { - mPipHandler.syncPipSurfaceState(info, startTransaction, finishTransaction); - } - if (mSplitHandler != null && mSplitHandler.isSplitActive()) { - mSplitHandler.updateSurfaces(startTransaction); - } - return mUnfoldHandler.startAnimation( - mixed.mTransition, info, startTransaction, finishTransaction, finishCB); + return mixed.startSubAnimation(keyguardHandler, info, startTransaction, finishTransaction); } /** Use to when split use intent to enter, check if this enter transition should be mixed or @@ -947,65 +1106,13 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, @NonNull Transitions.TransitionFinishCallback finishCallback) { for (int i = 0; i < mActiveTransitions.size(); ++i) { if (mActiveTransitions.get(i).mTransition != mergeTarget) continue; + MixedTransition mixed = mActiveTransitions.get(i); if (mixed.mInFlightSubAnimations <= 0) { // Already done, so no need to end it. return; } - if (mixed.mType == MixedTransition.TYPE_DISPLAY_AND_SPLIT_CHANGE) { - // queue since no actual animation. - } else if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { - if (mixed.mAnimType == MixedTransition.ANIM_TYPE_GOING_HOME) { - boolean ended = mSplitHandler.end(); - // If split couldn't end (because it is remote), then don't end everything else - // since we have to play out the animation anyways. - if (!ended) return; - mPipHandler.end(); - if (mixed.mLeftoversHandler != null) { - mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } - } else { - mPipHandler.end(); - } - } else if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) { - mPipHandler.end(); - mActivityEmbeddingController.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { - mPipHandler.end(); - if (mixed.mLeftoversHandler != null) { - mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } - } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { - if (mSplitHandler.isPendingEnter(transition)) { - // Recents -> enter-split means that we are switching from one pair to - // another pair. - mixed.mAnimType = MixedTransition.ANIM_TYPE_PAIR_TO_PAIR; - } - mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) { - mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); - } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_KEYGUARD) { - if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) { - handoverTransitionLeashes(mixed, info, t, mixed.mFinishT); - if (animateKeyguard(mixed, info, t, mixed.mFinishT, mixed.mFinishCB)) { - finishCallback.onTransitionFinished(null); - } - } - mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { - mixed.mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, - finishCallback); - } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) { - mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback); - } else { - throw new IllegalStateException("Playing a mixed transition with unknown type? " - + mixed.mType); - } + mixed.mergeAnimation(transition, info, t, mergeTarget, finishCallback); } } @@ -1018,46 +1125,30 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, mixed = mActiveTransitions.remove(i); break; } - if (mixed == null) return; - if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_SPLIT) { - mPipHandler.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) { - mPipHandler.onTransitionConsumed(transition, aborted, finishT); - mActivityEmbeddingController.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) { - mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) { - mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) { - mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) { - mixed.mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT); - } else if (mixed.mType == MixedTransition.TYPE_UNFOLD) { - mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT); - } - if (mixed.mHasRequestToRemote) { - mPlayer.getRemoteTransitionHandler().onTransitionConsumed(transition, aborted, finishT); + if (mixed != null) { + mixed.onTransitionConsumed(transition, aborted, finishT); } } /** - * Update an incoming {@link TransitionInfo} with the leashes from an ongoing - * {@link MixedTransition} so that it can take over some parts of the animation without + * Update an incoming {@link TransitionInfo} with the leashes from an existing + * {@link TransitionInfo} so that it can take over some parts of the animation without * reparenting to new transition roots. */ - private static void handoverTransitionLeashes(@NonNull MixedTransition mixed, - @NonNull TransitionInfo info, + private static void handoverTransitionLeashes( + @NonNull TransitionInfo from, + @NonNull TransitionInfo to, @NonNull SurfaceControl.Transaction startT, @NonNull SurfaceControl.Transaction finishT) { // Show the roots in case they contain new changes not present in the original transition. - for (int j = info.getRootCount() - 1; j >= 0; --j) { - startT.show(info.getRoot(j).getLeash()); + for (int j = to.getRootCount() - 1; j >= 0; --j) { + startT.show(to.getRoot(j).getLeash()); } // Find all of the leashes from the original transition. Map<WindowContainerToken, TransitionInfo.Change> originalChanges = new ArrayMap<>(); - for (TransitionInfo.Change oldChange : mixed.mInfo.getChanges()) { + for (TransitionInfo.Change oldChange : from.getChanges()) { if (oldChange.getContainer() != null) { originalChanges.put(oldChange.getContainer(), oldChange); } @@ -1065,9 +1156,10 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler, // Merge the animation leashes by re-using the original ones if we see the same container // in the new transition and the old. - for (TransitionInfo.Change newChange : info.getChanges()) { + for (TransitionInfo.Change newChange : to.getChanges()) { if (originalChanges.containsKey(newChange.getContainer())) { - final TransitionInfo.Change oldChange = originalChanges.get(newChange.getContainer()); + final TransitionInfo.Change oldChange = originalChanges.get( + newChange.getContainer()); startT.reparent(newChange.getLeash(), null); newChange.setLeash(oldChange.getLeash()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java index d7cb490ed0cb..4aed7c449750 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldAnimationController.java @@ -16,6 +16,8 @@ package com.android.wm.shell.unfold; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + import android.annotation.NonNull; import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; @@ -28,11 +30,11 @@ import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener; import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator; +import dagger.Lazy; + import java.util.List; import java.util.Optional; -import dagger.Lazy; - /** * Manages fold/unfold animations of tasks on foldable devices. * When folding or unfolding a foldable device we play animations that @@ -228,7 +230,8 @@ public class UnfoldAnimationController implements UnfoldListener { } private void maybeResetTask(UnfoldTaskAnimator animator, TaskInfo taskInfo) { - if (!mIsInStageChange) { + // TODO(b/311084698): the windowing mode check is added here as a work around. + if (!mIsInStageChange || taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) { // No need to resetTask if there is no ongoing state change. return; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index d07c64670bd2..aabc1cfb5875 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -421,9 +421,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId)); - if (!mHasLongClicked) { + if (!mHasLongClicked && id != R.id.maximize_window) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); - decoration.closeMaximizeMenu(); + decoration.closeMaximizeMenuIfNeeded(e); } final long eventDuration = e.getEventTime() - e.getDownTime(); @@ -502,7 +502,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)); mDesktopTasksController.ifPresent(c -> c.onDragPositioningMove(taskInfo, decoration.mTaskSurface, - new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)), + e.getRawX(dragPointerIdx), newTaskBounds)); mIsDragging = true; mShouldClick = false; @@ -643,7 +643,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { handleCaptionThroughStatusBar(ev, relevantDecor); } } - handleEventOutsideFocusedCaption(ev, relevantDecor); + handleEventOutsideCaption(ev, relevantDecor); // Prevent status bar from reacting to a caption drag. if (DesktopModeStatus.isEnabled()) { if (mTransitionDragActive) { @@ -652,11 +652,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } - // If an UP/CANCEL action is received outside of caption bounds, turn off handle menu - private void handleEventOutsideFocusedCaption(MotionEvent ev, + /** + * If an UP/CANCEL action is received outside of the caption bounds, close the handle and + * maximize the menu. + * + * @param relevantDecor the window decoration of the focused task's caption. This method only + * handles motion events outside this caption's bounds. + */ + private void handleEventOutsideCaption(MotionEvent ev, DesktopModeWindowDecoration relevantDecor) { // Returns if event occurs within caption - if (relevantDecor == null || relevantDecor.checkTouchEventInCaptionHandle(ev)) { + if (relevantDecor == null || relevantDecor.checkTouchEventInCaption(ev)) { return; } @@ -692,7 +698,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } if (dragFromStatusBarAllowed - && relevantDecor.checkTouchEventInCaptionHandle(ev)) { + && relevantDecor.checkTouchEventInFocusedCaptionHandle(ev)) { mTransitionDragActive = true; } } @@ -731,9 +737,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } if (mTransitionDragActive) { mDesktopTasksController.ifPresent( - c -> c.onDragPositioningMoveThroughStatusBar( + c -> c.updateVisualIndicator( relevantDecor.mTaskInfo, - relevantDecor.mTaskSurface, ev.getY())); + relevantDecor.mTaskSurface, ev.getX(), ev.getY())); final int statusBarHeight = getStatusBarHeight( relevantDecor.mTaskInfo.displayId); if (ev.getY() > statusBarHeight) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 5f77192fb623..53f806ccabee 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -612,8 +612,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin void closeMaximizeMenuIfNeeded(MotionEvent ev) { if (!isMaximizeMenuActive()) return; - final PointF inputPoint = offsetCaptionLocation(ev); - if (!mMaximizeMenu.isValidMenuInput(inputPoint)) { + if (!mMaximizeMenu.isValidMenuInput(ev)) { closeMaximizeMenu(); } } @@ -639,20 +638,34 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } /** - * Checks if motion event occurs in the caption handle area. This should be used in cases where + * Checks if motion event occurs in the caption handle area of a focused caption (the caption on + * a task in fullscreen or in multi-windowing mode). This should be used in cases where * onTouchListener will not work (i.e. when caption is in status bar area). * * @param ev the {@link MotionEvent} to check - * @return {@code true} if event is inside the specified view, {@code false} if not + * @return {@code true} if event is inside caption handle view, {@code false} if not */ - boolean checkTouchEventInCaptionHandle(MotionEvent ev) { + boolean checkTouchEventInFocusedCaptionHandle(MotionEvent ev) { if (isHandleMenuActive() || !(mWindowDecorViewHolder instanceof DesktopModeFocusedWindowDecorationViewHolder)) { return false; } + + return checkTouchEventInCaption(ev); + } + + /** + * Checks if touch event occurs in caption. + * + * @param ev the {@link MotionEvent} to check + * @return {@code true} if event is inside caption view, {@code false} if not + */ + boolean checkTouchEventInCaption(MotionEvent ev) { final PointF inputPoint = offsetCaptionLocation(ev); - return ((DesktopModeFocusedWindowDecorationViewHolder) mWindowDecorViewHolder) - .pointInCaption(inputPoint, mResult.mCaptionX); + return inputPoint.x >= mResult.mCaptionX + && inputPoint.x <= mResult.mCaptionX + mResult.mCaptionWidth + && inputPoint.y >= 0 + && inputPoint.y <= mResult.mCaptionHeight; } /** @@ -668,7 +681,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin // Click if point in caption handle view final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); final View handle = caption.findViewById(R.id.caption_handle); - if (checkTouchEventInCaptionHandle(ev)) { + if (checkTouchEventInFocusedCaptionHandle(ev)) { mOnCaptionButtonClickListener.onClick(handle); } } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt index 921708faab16..794b357c9f16 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt @@ -22,10 +22,10 @@ import android.content.res.Resources import android.graphics.PixelFormat import android.graphics.PointF import android.view.LayoutInflater +import android.view.MotionEvent import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import android.view.SurfaceControlViewHost -import android.view.View import android.view.View.OnClickListener import android.view.WindowManager import android.view.WindowlessWindowManager @@ -62,6 +62,8 @@ class MaximizeMenu( private val cornerRadius = loadDimensionPixelSize( R.dimen.desktop_mode_maximize_menu_corner_radius ).toFloat() + private val menuWidth = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_width) + private val menuHeight = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_height) /** Position the menu relative to the caption's position. */ fun positionMenu(position: PointF, t: Transaction) { @@ -95,8 +97,6 @@ class MaximizeMenu( .setName("Maximize Menu") .setContainerLayer() .build() - val menuWidth = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_width) - val menuHeight = loadDimensionPixelSize(R.dimen.desktop_mode_maximize_menu_height) val lp = WindowManager.LayoutParams( menuWidth, menuHeight, @@ -160,14 +160,11 @@ class MaximizeMenu( * * @param inputPoint the input to compare against. */ - fun isValidMenuInput(inputPoint: PointF): Boolean { - val menuView = maximizeMenu?.mWindowViewHost?.view ?: return true - return !viewsLaidOut() || pointInView(menuView, inputPoint.x - menuPosition.x, - inputPoint.y - menuPosition.y) - } - - private fun pointInView(v: View, x: Float, y: Float): Boolean { - return v.left <= x && v.right >= x && v.top <= y && v.bottom >= y + fun isValidMenuInput(ev: MotionEvent): Boolean { + val x = ev.rawX + val y = ev.rawY + return !viewsLaidOut() || (menuPosition.x <= x && menuPosition.x + menuWidth >= x && + menuPosition.y <= y && menuPosition.y + menuHeight >= y) } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index 6a9258c68acf..afe837e834f0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -279,11 +279,12 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } outResult.mCaptionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId); - final int captionWidth = params.mCaptionWidthId != Resources.ID_NULL + outResult.mCaptionWidth = params.mCaptionWidthId != Resources.ID_NULL ? loadDimensionPixelSize(resources, params.mCaptionWidthId) : taskBounds.width(); - outResult.mCaptionX = (outResult.mWidth - captionWidth) / 2; + outResult.mCaptionX = (outResult.mWidth - outResult.mCaptionWidth) / 2; - startT.setWindowCrop(mCaptionContainerSurface, captionWidth, outResult.mCaptionHeight) + startT.setWindowCrop(mCaptionContainerSurface, outResult.mCaptionWidth, + outResult.mCaptionHeight) .setPosition(mCaptionContainerSurface, outResult.mCaptionX, 0 /* y */) .setLayer(mCaptionContainerSurface, CAPTION_LAYER_Z_ORDER) .show(mCaptionContainerSurface); @@ -356,7 +357,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Caption view mCaptionWindowManager.setConfiguration(taskConfig); final WindowManager.LayoutParams lp = - new WindowManager.LayoutParams(captionWidth, outResult.mCaptionHeight, + new WindowManager.LayoutParams(outResult.mCaptionWidth, outResult.mCaptionHeight, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); lp.setTitle("Caption of Task=" + mTaskInfo.taskId); @@ -578,6 +579,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> static class RelayoutResult<T extends View & TaskFocusStateConsumer> { int mCaptionHeight; + int mCaptionWidth; int mCaptionX; int mWidth; int mHeight; @@ -587,6 +589,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> mWidth = 0; mHeight = 0; mCaptionHeight = 0; + mCaptionWidth = 0; mCaptionX = 0; mRootView = null; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt index 5f77022a577d..6dcae2776847 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt @@ -5,7 +5,6 @@ import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.res.ColorStateList import android.graphics.Color -import android.graphics.PointF import android.view.View import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS import android.widget.ImageButton @@ -47,17 +46,6 @@ internal class DesktopModeFocusedWindowDecorationViewHolder( animateCaptionHandleAlpha(startValue = 0f, endValue = 1f) } - /** - * Returns true if input point is in the caption's view. - * @param inputPoint the input point relative to the task in full "focus" (i.e. fullscreen). - */ - fun pointInCaption(inputPoint: PointF, captionX: Int): Boolean { - return inputPoint.x >= captionX && - inputPoint.x <= captionX + captionView.width && - inputPoint.y >= 0 && - inputPoint.y <= captionView.height - } - private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int { return if (shouldUseLightCaptionColors(taskInfo)) { context.getColor(R.color.desktop_mode_caption_handle_bar_light) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index 182a9089d040..be771712834f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -101,7 +101,8 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran override fun pipLayerReduces() { flicker.assertLayers { val pipLayerList = - this.layers { standardAppHelper.layerMatchesAnyOf(it) && it.isVisible } + this.layers { standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) + && it.isVisible } pipLayerList.zipWithNext { previous, current -> current.visibleRegion.notBiggerThan(previous.visibleRegion.region) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java deleted file mode 100644 index 6ebee730756e..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open 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.bubbles; - -import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.util.concurrent.MoreExecutors.directExecutor; - -import static org.mockito.Mockito.mock; - -import android.content.Intent; -import android.content.pm.ShortcutInfo; -import android.graphics.Insets; -import android.graphics.PointF; -import android.graphics.Rect; -import android.graphics.RectF; -import android.os.UserHandle; -import android.testing.AndroidTestingRunner; -import android.view.WindowManager; - -import androidx.test.filters.SmallTest; - -import com.android.wm.shell.R; -import com.android.wm.shell.ShellTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * Tests operations and the resulting state managed by {@link BubblePositioner}. - */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -public class BubblePositionerTest extends ShellTestCase { - - private BubblePositioner mPositioner; - - @Before - public void setUp() { - WindowManager windowManager = mContext.getSystemService(WindowManager.class); - mPositioner = new BubblePositioner(mContext, windowManager); - } - - @Test - public void testUpdate() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1000, 1200); - Rect availableRect = new Rect(screenBounds); - availableRect.inset(insets); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.getAvailableRect()).isEqualTo(availableRect); - assertThat(mPositioner.isLandscape()).isFalse(); - assertThat(mPositioner.isLargeScreen()).isFalse(); - assertThat(mPositioner.getInsets()).isEqualTo(insets); - } - - @Test - public void testShowBubblesVertically_phonePortrait() { - DeviceConfig deviceConfig = new ConfigBuilder().build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.showBubblesVertically()).isFalse(); - } - - @Test - public void testShowBubblesVertically_phoneLandscape() { - DeviceConfig deviceConfig = new ConfigBuilder().setLandscape().build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.isLandscape()).isTrue(); - assertThat(mPositioner.showBubblesVertically()).isTrue(); - } - - @Test - public void testShowBubblesVertically_tablet() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.showBubblesVertically()).isTrue(); - } - - /** If a resting position hasn't been set, calling it will return the default position. */ - @Test - public void testGetRestingPosition_returnsDefaultPosition() { - DeviceConfig deviceConfig = new ConfigBuilder().build(); - mPositioner.update(deviceConfig); - - PointF restingPosition = mPositioner.getRestingPosition(); - PointF defaultPosition = mPositioner.getDefaultStartPosition(); - - assertThat(restingPosition).isEqualTo(defaultPosition); - } - - /** If a resting position has been set, it'll return that instead of the default position. */ - @Test - public void testGetRestingPosition_returnsRestingPosition() { - DeviceConfig deviceConfig = new ConfigBuilder().build(); - mPositioner.update(deviceConfig); - - PointF restingPosition = new PointF(100, 100); - mPositioner.setRestingPosition(restingPosition); - - assertThat(mPositioner.getRestingPosition()).isEqualTo(restingPosition); - } - - /** Test that the default resting position on phone is in upper left. */ - @Test - public void testGetRestingPosition_bubble_onPhone() { - DeviceConfig deviceConfig = new ConfigBuilder().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF restingPosition = mPositioner.getRestingPosition(); - - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left); - assertThat(restingPosition.y).isEqualTo(getDefaultYPosition()); - } - - @Test - public void testGetRestingPosition_bubble_onPhone_RTL() { - DeviceConfig deviceConfig = new ConfigBuilder().setRtl().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF restingPosition = mPositioner.getRestingPosition(); - - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right); - assertThat(restingPosition.y).isEqualTo(getDefaultYPosition()); - } - - /** Test that the default resting position on tablet is middle left. */ - @Test - public void testGetRestingPosition_chatBubble_onTablet() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF restingPosition = mPositioner.getRestingPosition(); - - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left); - assertThat(restingPosition.y).isEqualTo(getDefaultYPosition()); - } - - @Test - public void testGetRestingPosition_chatBubble_onTablet_RTL() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF restingPosition = mPositioner.getRestingPosition(); - - assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right); - assertThat(restingPosition.y).isEqualTo(getDefaultYPosition()); - } - - /** Test that the default resting position on tablet is middle right. */ - @Test - public void testGetDefaultPosition_appBubble_onTablet() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF startPosition = mPositioner.getDefaultStartPosition(true /* isAppBubble */); - - assertThat(startPosition.x).isEqualTo(allowableStackRegion.right); - assertThat(startPosition.y).isEqualTo(getDefaultYPosition()); - } - - @Test - public void testGetRestingPosition_appBubble_onTablet_RTL() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build(); - mPositioner.update(deviceConfig); - - RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - PointF startPosition = mPositioner.getDefaultStartPosition(true /* isAppBubble */); - - assertThat(startPosition.x).isEqualTo(allowableStackRegion.left); - assertThat(startPosition.y).isEqualTo(getDefaultYPosition()); - } - - @Test - public void testHasUserModifiedDefaultPosition_false() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse(); - - mPositioner.setRestingPosition(mPositioner.getDefaultStartPosition()); - - assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse(); - } - - @Test - public void testHasUserModifiedDefaultPosition_true() { - DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse(); - - mPositioner.setRestingPosition(new PointF(0, 100)); - - assertThat(mPositioner.hasUserModifiedDefaultPosition()).isTrue(); - } - - @Test - public void testGetExpandedViewHeight_max() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT); - } - - @Test - public void testGetExpandedViewHeight_customHeight_valid() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - final int minHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_expanded_default_height); - Bubble bubble = new Bubble("key", - mock(ShortcutInfo.class), - minHeight + 100 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor(), - mock(Bubbles.BubbleMetadataFlagListener.class)); - - // Ensure the height is the same as the desired value - assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo( - bubble.getDesiredHeight(mContext)); - } - - - @Test - public void testGetExpandedViewHeight_customHeight_tooSmall() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Bubble bubble = new Bubble("key", - mock(ShortcutInfo.class), - 10 /* desiredHeight */, - 0 /* desiredHeightResId */, - "title", - 0 /* taskId */, - null /* locus */, - true /* isDismissable */, - directExecutor(), - mock(Bubbles.BubbleMetadataFlagListener.class)); - - // Ensure the height is the same as the minimum value - final int minHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_expanded_default_height); - assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight); - } - - @Test - public void testGetMaxExpandedViewHeight_onLargeTablet() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - int manageButtonHeight = - mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height); - int pointerWidth = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_pointer_width); - int expandedViewPadding = mContext.getResources().getDimensionPixelSize(R - .dimen.bubble_expanded_view_padding); - float expectedHeight = 1800 - 2 * 20 - manageButtonHeight - pointerWidth - - expandedViewPadding * 2; - assertThat(((float) mPositioner.getMaxExpandedViewHeight(false /* isOverflow */))) - .isWithin(0.1f).of(expectedHeight); - } - - @Test - public void testAreBubblesBottomAligned_largeScreen_true() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.areBubblesBottomAligned()).isTrue(); - } - - @Test - public void testAreBubblesBottomAligned_largeScreen_false() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setLandscape() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.areBubblesBottomAligned()).isFalse(); - } - - @Test - public void testAreBubblesBottomAligned_smallTablet_false() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setSmallTablet() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.areBubblesBottomAligned()).isFalse(); - } - - @Test - public void testAreBubblesBottomAligned_phone_false() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - assertThat(mPositioner.areBubblesBottomAligned()).isFalse(); - } - - @Test - public void testExpandedViewY_phoneLandscape() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLandscape() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - // This bubble will have max height so it'll always be top aligned - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(mPositioner.getExpandedViewYTopAligned()); - } - - @Test - public void testExpandedViewY_phonePortrait() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - // Always top aligned in phone portrait - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(mPositioner.getExpandedViewYTopAligned()); - } - - @Test - public void testExpandedViewY_smallTabletLandscape() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setSmallTablet() - .setLandscape() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - // This bubble will have max height which is always top aligned on small tablets - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(mPositioner.getExpandedViewYTopAligned()); - } - - @Test - public void testExpandedViewY_smallTabletPortrait() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setSmallTablet() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - // This bubble will have max height which is always top aligned on small tablets - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(mPositioner.getExpandedViewYTopAligned()); - } - - @Test - public void testExpandedViewY_largeScreenLandscape() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setLandscape() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - // This bubble will have max height which is always top aligned on landscape, large tablet - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(mPositioner.getExpandedViewYTopAligned()); - } - - @Test - public void testExpandedViewY_largeScreenPortrait() { - Insets insets = Insets.of(10, 20, 5, 15); - Rect screenBounds = new Rect(0, 0, 1800, 2600); - - DeviceConfig deviceConfig = new ConfigBuilder() - .setLargeScreen() - .setInsets(insets) - .setScreenBounds(screenBounds) - .build(); - mPositioner.update(deviceConfig); - - Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName()); - Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor()); - - int manageButtonHeight = - mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height); - int manageButtonPlusMargin = manageButtonHeight + 2 - * mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_manage_button_margin); - int pointerWidth = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_pointer_width); - - final float expectedExpandedViewY = mPositioner.getAvailableRect().bottom - - manageButtonPlusMargin - - mPositioner.getExpandedViewHeightForLargeScreen() - - pointerWidth; - - // Bubbles are bottom aligned on portrait, large tablet - assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */)) - .isEqualTo(expectedExpandedViewY); - } - - /** - * Calculates the Y position bubbles should be placed based on the config. Based on - * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and - * {@link BubbleStackView.RelativeStackPosition}. - */ - private float getDefaultYPosition() { - final boolean isTablet = mPositioner.isLargeScreen(); - - // On tablet the position is centered, on phone it is an offset from the top. - final float desiredY = isTablet - ? mPositioner.getScreenRect().height() / 2f - (mPositioner.getBubbleSize() / 2f) - : mContext.getResources().getDimensionPixelOffset( - R.dimen.bubble_stack_starting_offset_y); - // Since we're visually centering the bubbles on tablet, use total screen height rather - // than the available height. - final float height = isTablet - ? mPositioner.getScreenRect().height() - : mPositioner.getAvailableRect().height(); - float offsetPercent = desiredY / height; - offsetPercent = Math.max(0f, Math.min(1f, offsetPercent)); - final RectF allowableStackRegion = - mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */); - return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent; - } - - /** - * Sets up window manager to return config values based on what you need for the test. - * By default it sets up a portrait phone without any insets. - */ - private static class ConfigBuilder { - private Rect mScreenBounds = new Rect(0, 0, 1000, 2000); - private boolean mIsLargeScreen = false; - private boolean mIsSmallTablet = false; - private boolean mIsLandscape = false; - private boolean mIsRtl = false; - private Insets mInsets = Insets.of(0, 0, 0, 0); - - public ConfigBuilder setScreenBounds(Rect screenBounds) { - mScreenBounds = screenBounds; - return this; - } - - public ConfigBuilder setLargeScreen() { - mIsLargeScreen = true; - return this; - } - - public ConfigBuilder setSmallTablet() { - mIsSmallTablet = true; - return this; - } - - public ConfigBuilder setLandscape() { - mIsLandscape = true; - return this; - } - - public ConfigBuilder setRtl() { - mIsRtl = true; - return this; - } - - public ConfigBuilder setInsets(Insets insets) { - mInsets = insets; - return this; - } - - private DeviceConfig build() { - return new DeviceConfig(mIsLargeScreen, mIsSmallTablet, mIsLandscape, mIsRtl, - mScreenBounds, mInsets); - } - } -} diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp index 2f28363aedc7..77800a305f02 100644 --- a/libs/androidfw/Android.bp +++ b/libs/androidfw/Android.bp @@ -31,6 +31,12 @@ license { ], } +cc_aconfig_library { + name: "backup_flags_cc_lib", + host_supported: true, + aconfig_declarations: "backup_flags", +} + cc_defaults { name: "libandroidfw_defaults", cpp_std: "gnu++2b", @@ -115,7 +121,10 @@ cc_library { "libutils", "libz", ], - static_libs: ["libziparchive_for_incfs"], + static_libs: [ + "libziparchive_for_incfs", + "backup_flags_cc_lib", + ], static: { enabled: false, }, diff --git a/libs/androidfw/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp index 1a6a952492f6..a1e7c2ffc1b1 100644 --- a/libs/androidfw/BackupHelpers.cpp +++ b/libs/androidfw/BackupHelpers.cpp @@ -36,6 +36,9 @@ #include <utils/KeyedVector.h> #include <utils/String8.h> +#include <com_android_server_backup.h> +namespace backup_flags = com::android::server::backup; + namespace android { #define MAGIC0 0x70616e53 // Snap @@ -214,7 +217,7 @@ write_update_file(BackupDataWriter* dataStream, int fd, int mode, const String8& { LOGP("write_update_file %s (%s) : mode 0%o\n", realFilename, key.c_str(), mode); - const int bufsize = 4*1024; + const int bufsize = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (4*1024); int err; int amt; int fileSize; @@ -550,7 +553,8 @@ int write_tarfile(const String8& packageName, const String8& domain, } // read/write up to this much at a time. - const size_t BUFSIZE = 32 * 1024; + const size_t BUFSIZE = backup_flags::enable_max_size_writes_to_pipes() ? (64*1024) : (32*1024); + char* buf = (char *)calloc(1,BUFSIZE); const size_t PAXHEADER_OFFSET = 512; const size_t PAXHEADER_SIZE = 512; @@ -726,7 +730,7 @@ done: -#define RESTORE_BUF_SIZE (8*1024) +const size_t RESTORE_BUF_SIZE = backup_flags::enable_max_size_writes_to_pipes() ? 64*1024 : 8*1024; RestoreHelperBase::RestoreHelperBase() { diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index 6c3172a26751..d58c872dbc56 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -56,6 +56,7 @@ std::optional<std::int32_t> render_ahead() { bool Properties::debugLayersUpdates = false; bool Properties::debugOverdraw = false; +bool Properties::debugTraceGpuResourceCategories = false; bool Properties::showDirtyRegions = false; bool Properties::skipEmptyFrames = true; bool Properties::useBufferAge = true; @@ -151,10 +152,12 @@ bool Properties::load() { skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false); - SkAndroidFrameworkTraceUtil::setEnableTracing( - base::GetBoolProperty(PROPERTY_SKIA_TRACING_ENABLED, false)); + bool skiaBroadTracing = base::GetBoolProperty(PROPERTY_SKIA_TRACING_ENABLED, false); + SkAndroidFrameworkTraceUtil::setEnableTracing(skiaBroadTracing); SkAndroidFrameworkTraceUtil::setUsePerfettoTrackEvents( base::GetBoolProperty(PROPERTY_SKIA_USE_PERFETTO_TRACK_EVENTS, false)); + debugTraceGpuResourceCategories = + base::GetBoolProperty(PROPERTY_TRACE_GPU_RESOURCES, skiaBroadTracing); runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index bca57e9e4678..b956facf6f90 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -143,6 +143,15 @@ enum DebugLevel { #define PROPERTY_CAPTURE_SKP_ENABLED "debug.hwui.capture_skp_enabled" /** + * Might split Skia's GPU resource utilization into separate tracing tracks (slow). + * + * Aggregate total and purgeable numbers will still be reported under a "misc" track when this is + * disabled, they just won't be split into distinct categories. Results may vary depending on GPU + * backend/API, and the category mappings defined in ATraceMemoryDump's hardcoded sResourceMap. + */ +#define PROPERTY_TRACE_GPU_RESOURCES "debug.hwui.trace_gpu_resources" + +/** * Allows broad recording of Skia drawing commands. * * If disabled, a very minimal set of trace events *may* be recorded. @@ -254,6 +263,7 @@ public: static bool debugLayersUpdates; static bool debugOverdraw; + static bool debugTraceGpuResourceCategories; static bool showDirtyRegions; // TODO: Remove after stabilization period static bool skipEmptyFrames; diff --git a/libs/hwui/aconfig/hwui_flags.aconfig b/libs/hwui/aconfig/hwui_flags.aconfig index c156c46a5a9b..72ddeccd26b2 100644 --- a/libs/hwui/aconfig/hwui_flags.aconfig +++ b/libs/hwui/aconfig/hwui_flags.aconfig @@ -22,6 +22,13 @@ flag { } flag { + name: "high_contrast_text_small_text_rect" + namespace: "accessibility" + description: "Draw a solid rectangle background behind text instead of a stroke outline" + bug: "186567103" +} + +flag { name: "hdr_10bit_plus" namespace: "core_graphics" description: "Use 10101010 and FP16 formats for HDR-UI when available" diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index 80b6c0385fca..e9f4b81c7624 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -18,6 +18,7 @@ #include <SkFontMetrics.h> #include <SkRRect.h> +#include <minikin/MinikinRect.h> #include "FeatureFlags.h" #include "MinikinUtils.h" @@ -107,7 +108,13 @@ void Canvas::drawText(const uint16_t* text, int textSize, int start, int count, // care of all alignment. paint.setTextAlign(Paint::kLeft_Align); - DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance()); + minikin::MinikinRect bounds; + // We only need the bounds to draw a rectangular background in high contrast mode. Let's save + // the cycles otherwise. + if (flags::high_contrast_text_small_text_rect() && isHighContrastText()) { + MinikinUtils::getBounds(&paint, bidiFlags, typeface, text, textSize, &bounds); + } + DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance(), bounds); MinikinUtils::forFontRun(layout, &paint, f); if (text_feature::fix_double_underline()) { diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h index 8f999904a8ab..ba6543988a7b 100644 --- a/libs/hwui/hwui/DrawTextFunctor.h +++ b/libs/hwui/hwui/DrawTextFunctor.h @@ -33,6 +33,8 @@ namespace flags = com::android::graphics::hwui::flags; namespace android { +inline constexpr int kHighContrastTextBorderWidth = 4; + static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness, const Paint& paint, Canvas* canvas) { const SkScalar strokeWidth = fmax(thickness, 1.0f); @@ -45,15 +47,26 @@ static void simplifyPaint(int color, Paint* paint) { paint->setShader(nullptr); paint->setColorFilter(nullptr); paint->setLooper(nullptr); - paint->setStrokeWidth(4 + 0.04 * paint->getSkFont().getSize()); + paint->setStrokeWidth(kHighContrastTextBorderWidth + 0.04 * paint->getSkFont().getSize()); paint->setStrokeJoin(SkPaint::kRound_Join); paint->setLooper(nullptr); } class DrawTextFunctor { public: + /** + * Creates a Functor to draw the given text layout. + * + * @param layout + * @param canvas + * @param paint + * @param x + * @param y + * @param totalAdvance + * @param bounds bounds of the text. Only required if high contrast text mode is enabled. + */ DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, const Paint& paint, float x, - float y, float totalAdvance) + float y, float totalAdvance, const minikin::MinikinRect& bounds) : layout(layout) , canvas(canvas) , paint(paint) @@ -61,7 +74,8 @@ public: , y(y) , totalAdvance(totalAdvance) , underlinePosition(0) - , underlineThickness(0) {} + , underlineThickness(0) + , bounds(bounds) {} void operator()(size_t start, size_t end) { auto glyphFunc = [&](uint16_t* text, float* positions) { @@ -91,7 +105,16 @@ public: Paint outlinePaint(paint); simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint); outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style); - canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance); + if (flags::high_contrast_text_small_text_rect()) { + auto bgBounds(bounds); + auto padding = kHighContrastTextBorderWidth + 0.1f * paint.getSkFont().getSize(); + bgBounds.offset(x, y); + canvas->drawRect(bgBounds.mLeft - padding, bgBounds.mTop - padding, + bgBounds.mRight + padding, bgBounds.mBottom + padding, + outlinePaint); + } else { + canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance); + } // inner gDrawTextBlobMode = DrawTextBlobMode::HctInner; @@ -146,6 +169,7 @@ private: float totalAdvance; float underlinePosition; float underlineThickness; + const minikin::MinikinRect& bounds; }; } // namespace android diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp index 7552b56d2ad6..833069f363c8 100644 --- a/libs/hwui/hwui/MinikinUtils.cpp +++ b/libs/hwui/hwui/MinikinUtils.cpp @@ -96,7 +96,7 @@ void MinikinUtils::getBounds(const Paint* paint, minikin::Bidi bidiFlags, const float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, float* advances, - minikin::MinikinRect* bounds) { + minikin::MinikinRect* bounds, uint32_t* clusterCount) { minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface); const minikin::U16StringPiece textBuf(buf, bufSize); const minikin::Range range(start, start + count); @@ -104,7 +104,7 @@ float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags, const minikin::EndHyphenEdit endHyphen = paint->getEndHyphenEdit(); return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen, - endHyphen, advances, bounds); + endHyphen, advances, bounds, clusterCount); } minikin::MinikinExtent MinikinUtils::getFontExtent(const Paint* paint, minikin::Bidi bidiFlags, diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h index 61bc881faa54..f8574ee50525 100644 --- a/libs/hwui/hwui/MinikinUtils.h +++ b/libs/hwui/hwui/MinikinUtils.h @@ -53,7 +53,7 @@ public: static float measureText(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize, - float* advances, minikin::MinikinRect* bounds); + float* advances, minikin::MinikinRect* bounds, uint32_t* clusterCount); static minikin::MinikinExtent getFontExtent(const Paint* paint, minikin::Bidi bidiFlags, const Typeface* typeface, const uint16_t* buf, diff --git a/libs/hwui/jni/Graphics.cpp b/libs/hwui/jni/Graphics.cpp index 7cc48661619a..8315c4c0dd4d 100644 --- a/libs/hwui/jni/Graphics.cpp +++ b/libs/hwui/jni/Graphics.cpp @@ -247,6 +247,9 @@ static jfieldID gFontMetricsInt_descent; static jfieldID gFontMetricsInt_bottom; static jfieldID gFontMetricsInt_leading; +static jclass gRunInfo_class; +static jfieldID gRunInfo_clusterCount; + /////////////////////////////////////////////////////////////////////////////// void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B) @@ -511,6 +514,10 @@ int GraphicsJNI::set_metrics_int(JNIEnv* env, jobject metrics, const SkFontMetri return descent - ascent + leading; } +void GraphicsJNI::set_cluster_count_to_run_info(JNIEnv* env, jobject runInfo, jint clusterCount) { + env->SetIntField(runInfo, gRunInfo_clusterCount, clusterCount); +} + /////////////////////////////////////////////////////////////////////////////////////////// jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, BitmapRegionDecoderWrapper* bitmap) { @@ -834,5 +841,10 @@ int register_android_graphics_Graphics(JNIEnv* env) gFontMetricsInt_bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I"); gFontMetricsInt_leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I"); + gRunInfo_class = FindClassOrDie(env, "android/graphics/Paint$RunInfo"); + gRunInfo_class = MakeGlobalRefOrDie(env, gRunInfo_class); + + gRunInfo_clusterCount = GetFieldIDOrDie(env, gRunInfo_class, "mClusterCount", "I"); + return 0; } diff --git a/libs/hwui/jni/GraphicsJNI.h b/libs/hwui/jni/GraphicsJNI.h index b9fff36d372e..b0a1074d6693 100644 --- a/libs/hwui/jni/GraphicsJNI.h +++ b/libs/hwui/jni/GraphicsJNI.h @@ -77,6 +77,8 @@ public: static SkRect* jrect_to_rect(JNIEnv*, jobject jrect, SkRect*); static void rect_to_jrectf(const SkRect&, JNIEnv*, jobject jrectf); + static void set_cluster_count_to_run_info(JNIEnv* env, jobject runInfo, jint clusterCount); + static void set_jpoint(JNIEnv*, jobject jrect, int x, int y); static SkIPoint* jpoint_to_ipoint(JNIEnv*, jobject jpoint, SkIPoint* point); diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp index d84b73d1a1ca..58d9d8b9def3 100644 --- a/libs/hwui/jni/Paint.cpp +++ b/libs/hwui/jni/Paint.cpp @@ -114,7 +114,7 @@ namespace PaintGlue { std::unique_ptr<float[]> advancesArray(new float[count]); MinikinUtils::measureText(&paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, - count, count, advancesArray.get(), nullptr); + count, count, advancesArray.get(), nullptr, nullptr); for (int i = 0; i < count; i++) { // traverse in the given direction @@ -206,7 +206,7 @@ namespace PaintGlue { } const float advance = MinikinUtils::measureText( paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, start, count, - contextCount, advancesArray.get(), nullptr); + contextCount, advancesArray.get(), nullptr, nullptr); if (advances) { env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get()); } @@ -244,7 +244,7 @@ namespace PaintGlue { minikin::Bidi bidiFlags = dir == 1 ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR; std::unique_ptr<float[]> advancesArray(new float[count]); MinikinUtils::measureText(paint, bidiFlags, typeface, text, start, count, start + count, - advancesArray.get(), nullptr); + advancesArray.get(), nullptr, nullptr); size_t result = minikin::GraphemeBreak::getTextRunCursor(advancesArray.get(), text, start, count, offset, moveOpt); return static_cast<jint>(result); @@ -508,7 +508,7 @@ namespace PaintGlue { static jfloat doRunAdvance(JNIEnv* env, const Paint* paint, const Typeface* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jint offset, jfloatArray advances, - jint advancesIndex, SkRect* drawBounds) { + jint advancesIndex, SkRect* drawBounds, uint32_t* clusterCount) { if (advances) { size_t advancesLength = env->GetArrayLength(advances); if ((size_t)(count + advancesIndex) > advancesLength) { @@ -519,9 +519,9 @@ namespace PaintGlue { minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR; minikin::MinikinRect bounds; if (offset == start + count && advances == nullptr) { - float result = - MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, - bufSize, nullptr, drawBounds ? &bounds : nullptr); + float result = MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, + bufSize, nullptr, + drawBounds ? &bounds : nullptr, clusterCount); if (drawBounds) { copyMinikinRectToSkRect(bounds, drawBounds); } @@ -529,7 +529,8 @@ namespace PaintGlue { } std::unique_ptr<float[]> advancesArray(new float[count]); MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize, - advancesArray.get(), drawBounds ? &bounds : nullptr); + advancesArray.get(), drawBounds ? &bounds : nullptr, + clusterCount); if (drawBounds) { copyMinikinRectToSkRect(bounds, drawBounds); @@ -549,7 +550,7 @@ namespace PaintGlue { ScopedCharArrayRO textArray(env, text); jfloat result = doRunAdvance(env, paint, typeface, textArray.get() + contextStart, start - contextStart, end - start, contextEnd - contextStart, - isRtl, offset - contextStart, nullptr, 0, nullptr); + isRtl, offset - contextStart, nullptr, 0, nullptr, nullptr); return result; } @@ -558,27 +559,41 @@ namespace PaintGlue { jint contextStart, jint contextEnd, jboolean isRtl, jint offset, jfloatArray advances, jint advancesIndex, - jobject drawBounds) { + jobject drawBounds, jobject runInfo) { const Paint* paint = reinterpret_cast<Paint*>(paintHandle); const Typeface* typeface = paint->getAndroidTypeface(); ScopedCharArrayRO textArray(env, text); SkRect skDrawBounds; + uint32_t clusterCount = 0; jfloat result = doRunAdvance(env, paint, typeface, textArray.get() + contextStart, start - contextStart, end - start, contextEnd - contextStart, isRtl, offset - contextStart, advances, advancesIndex, - drawBounds ? &skDrawBounds : nullptr); + drawBounds ? &skDrawBounds : nullptr, &clusterCount); if (drawBounds != nullptr) { GraphicsJNI::rect_to_jrectf(skDrawBounds, env, drawBounds); } + if (runInfo) { + GraphicsJNI::set_cluster_count_to_run_info(env, runInfo, clusterCount); + } return result; } + // This method is kept for old Robolectric JNI signature used by SystemUIGoogleRoboRNGTests. + static jfloat getRunCharacterAdvance___CIIIIZI_FI_F_ForRobolectric( + JNIEnv* env, jclass cls, jlong paintHandle, jcharArray text, jint start, jint end, + jint contextStart, jint contextEnd, jboolean isRtl, jint offset, jfloatArray advances, + jint advancesIndex, jobject drawBounds) { + return getRunCharacterAdvance___CIIIIZI_FI_F(env, cls, paintHandle, text, start, end, + contextStart, contextEnd, isRtl, offset, + advances, advancesIndex, drawBounds, nullptr); + } + static jint doOffsetForAdvance(const Paint* paint, const Typeface* typeface, const jchar buf[], jint start, jint count, jint bufSize, jboolean isRtl, jfloat advance) { minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR; std::unique_ptr<float[]> advancesArray(new float[count]); MinikinUtils::measureText(paint, bidiFlags, typeface, buf, start, count, bufSize, - advancesArray.get(), nullptr); + advancesArray.get(), nullptr, nullptr); return minikin::getOffsetForAdvance(advancesArray.get(), buf, start, count, advance); } @@ -1145,8 +1160,11 @@ static const JNINativeMethod methods[] = { (void*)PaintGlue::getCharArrayBounds}, {"nHasGlyph", "(JILjava/lang/String;)Z", (void*)PaintGlue::hasGlyph}, {"nGetRunAdvance", "(J[CIIIIZI)F", (void*)PaintGlue::getRunAdvance___CIIIIZI_F}, - {"nGetRunCharacterAdvance", "(J[CIIIIZI[FILandroid/graphics/RectF;)F", + {"nGetRunCharacterAdvance", + "(J[CIIIIZI[FILandroid/graphics/RectF;Landroid/graphics/Paint$RunInfo;)F", (void*)PaintGlue::getRunCharacterAdvance___CIIIIZI_FI_F}, + {"nGetRunCharacterAdvance", "(J[CIIIIZI[FILandroid/graphics/RectF;)F", + (void*)PaintGlue::getRunCharacterAdvance___CIIIIZI_FI_F_ForRobolectric}, {"nGetOffsetForAdvance", "(J[CIIIIZF)I", (void*)PaintGlue::getOffsetForAdvance___CIIIIZF_I}, {"nGetFontMetricsIntForText", "(J[CIIIIZLandroid/graphics/Paint$FontMetricsInt;)V", (void*)PaintGlue::getFontMetricsIntForText___C}, diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp index 234f42d79cb7..756b937f7de3 100644 --- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp +++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp @@ -20,6 +20,8 @@ #include <cstring> +#include "GrDirectContext.h" + namespace android { namespace uirenderer { namespace skiapipeline { @@ -114,8 +116,16 @@ void ATraceMemoryDump::startFrame() { /** * logTraces reads from mCurrentValues and logs the counters with ATRACE. + * + * gpuMemoryIsAlreadyInDump must be true if GrDirectContext::dumpMemoryStatistics(...) was called + * with this tracer, false otherwise. Leaving this false allows this function to quickly query total + * and purgable GPU memory without the caller having to spend time in + * GrDirectContext::dumpMemoryStatistics(...) first, which iterates over every resource in the GPU + * cache. This can save significant time, but buckets all GPU memory into a single "misc" track, + * which may be a loss of granularity depending on the GPU backend and the categories defined in + * sResourceMap. */ -void ATraceMemoryDump::logTraces() { +void ATraceMemoryDump::logTraces(bool gpuMemoryIsAlreadyInDump, GrDirectContext* grContext) { // Accumulate data from last dumpName recordAndResetCountersIfNeeded(""); uint64_t hwui_all_frame_memory = 0; @@ -126,6 +136,20 @@ void ATraceMemoryDump::logTraces() { ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableMemory); } } + + if (!gpuMemoryIsAlreadyInDump && grContext) { + // Total GPU memory + int gpuResourceCount; + size_t gpuResourceBytes; + grContext->getResourceCacheUsage(&gpuResourceCount, &gpuResourceBytes); + hwui_all_frame_memory += (uint64_t)gpuResourceBytes; + ATRACE_INT64("HWUI Misc Memory", gpuResourceBytes); + + // Purgable subset of GPU memory + size_t purgeableGpuResourceBytes = grContext->getResourceCachePurgeableBytes(); + ATRACE_INT64("Purgeable HWUI Misc Memory", purgeableGpuResourceBytes); + } + ATRACE_INT64("HWUI All Memory", hwui_all_frame_memory); } diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.h b/libs/hwui/pipeline/skia/ATraceMemoryDump.h index 4592711dd5b5..777d1a2ddb5b 100644 --- a/libs/hwui/pipeline/skia/ATraceMemoryDump.h +++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.h @@ -16,6 +16,7 @@ #pragma once +#include <GrDirectContext.h> #include <SkString.h> #include <SkTraceMemoryDump.h> @@ -50,7 +51,7 @@ public: void startFrame(); - void logTraces(); + void logTraces(bool gpuMemoryIsAlreadyInDump, GrDirectContext* grContext); private: std::string mLastDumpName; diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index 30d461271c89..eb4d4948dc53 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -269,13 +269,14 @@ void CacheManager::onFrameCompleted() { cancelDestroyContext(); mFrameCompletions.next() = systemTime(CLOCK_MONOTONIC); if (ATRACE_ENABLED()) { + ATRACE_NAME("dumpingMemoryStatistics"); static skiapipeline::ATraceMemoryDump tracer; tracer.startFrame(); SkGraphics::DumpMemoryStatistics(&tracer); - if (mGrContext) { + if (mGrContext && Properties::debugTraceGpuResourceCategories) { mGrContext->dumpMemoryStatistics(&tracer); } - tracer.logTraces(); + tracer.logTraces(Properties::debugTraceGpuResourceCategories, mGrContext.get()); } } diff --git a/libs/hwui/tests/unit/UnderlineTest.cpp b/libs/hwui/tests/unit/UnderlineTest.cpp index c70a30477ecf..9911bfa70443 100644 --- a/libs/hwui/tests/unit/UnderlineTest.cpp +++ b/libs/hwui/tests/unit/UnderlineTest.cpp @@ -103,8 +103,9 @@ DrawTextFunctor processFunctor(const std::vector<uint16_t>& text, Paint* paint) // Create minikin::Layout std::unique_ptr<Typeface> typeface(makeTypeface()); minikin::Layout layout = doLayout(text, *paint, typeface.get()); + minikin::MinikinRect bounds; - DrawTextFunctor f(layout, &canvas, *paint, 0, 0, layout.getAdvance()); + DrawTextFunctor f(layout, &canvas, *paint, 0, 0, layout.getAdvance(), bounds); MinikinUtils::forFontRun(layout, paint, f); return f; } diff --git a/lint-baseline.xml b/lint-baseline.xml index 79b21551a76e..660884a18010 100644 --- a/lint-baseline.xml +++ b/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NonUserGetterCalled" @@ -433,7 +433,7 @@ <issue id="NonUserGetterCalled" message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. " - errorLine1=" boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) > 0;" + errorLine1=" boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) > 0;" errorLine2=" ~~~~~~"> <location file="frameworks/base/core/java/android/text/method/TextKeyListener.java" @@ -444,7 +444,7 @@ <issue id="NonUserGetterCalled" message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. " - errorLine1=" boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) > 0;" + errorLine1=" boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) > 0;" errorLine2=" ~~~~~~"> <location file="frameworks/base/core/java/android/text/method/TextKeyListener.java" @@ -455,7 +455,7 @@ <issue id="NonUserGetterCalled" message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. " - errorLine1=" boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) > 0;" + errorLine1=" boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) > 0;" errorLine2=" ~~~~~~"> <location file="frameworks/base/core/java/android/text/method/TextKeyListener.java" @@ -466,7 +466,7 @@ <issue id="NonUserGetterCalled" message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. " - errorLine1=" boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) > 0;" + errorLine1=" boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) > 0;" errorLine2=" ~~~~~~"> <location file="frameworks/base/core/java/android/text/method/TextKeyListener.java" @@ -562,4 +562,4 @@ column="74"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index ee2510ff9695..0d5af50d08b5 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -19,6 +19,7 @@ package com.android.internal.location; import android.Manifest; import android.annotation.RequiresPermission; import android.content.Context; +import android.content.pm.PackageManager; import android.location.LocationManager; import android.os.SystemClock; import android.telephony.TelephonyCallback; @@ -26,6 +27,8 @@ import android.telephony.TelephonyManager; import android.telephony.emergency.EmergencyNumber; import android.util.Log; +import com.android.internal.telephony.flags.Flags; + import java.util.concurrent.TimeUnit; /** @@ -139,8 +142,20 @@ public class GpsNetInitiatedHandler { (mCallEndElapsedRealtimeMillis > 0) && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) < emergencyExtensionMillis); - boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); - boolean isInEmergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); + boolean isInEmergencyCallback = false; + boolean isInEmergencySmsMode = false; + if (!Flags.enforceTelephonyFeatureMappingForPublicApis()) { + isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); + isInEmergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); + } else { + PackageManager pm = mContext.getPackageManager(); + if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) { + isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); + } + if (pm != null && pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)) { + isInEmergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); + } + } return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension || isInEmergencySmsMode; } diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 89792c7638cb..9616b5d44540 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -48,6 +48,7 @@ import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -141,7 +142,9 @@ public final class MediaRouter2 { * dispatch. This is only used to determine what callback a route should be assigned to (added, * removed, changed) in {@link #dispatchFilteredRoutesUpdatedOnHandler(List)}. */ - private volatile ArrayMap<String, MediaRoute2Info> mPreviousRoutes = new ArrayMap<>(); + private volatile ArrayMap<String, MediaRoute2Info> mPreviousFilteredRoutes = new ArrayMap<>(); + + private final Map<String, MediaRoute2Info> mPreviousUnfilteredRoutes = new ArrayMap<>(); /** * Stores the latest copy of exposed routes after filtering, sorting, and deduplication. Can be @@ -282,6 +285,8 @@ public final class MediaRouter2 { MediaRouter2 instance = sAppToProxyRouterMap.get(key); if (instance == null) { instance = new MediaRouter2(context, looper, clientPackageName, user); + // Register proxy router after instantiation to avoid race condition. + ((ProxyMediaRouter2Impl) instance.mImpl).registerProxyRouter(); sAppToProxyRouterMap.put(key, instance); } return instance; @@ -368,6 +373,7 @@ public final class MediaRouter2 { new SystemRoutingController( ProxyMediaRouter2Impl.getSystemSessionInfoImpl( mMediaRouterService, clientPackageName)); + mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user); } @@ -713,7 +719,7 @@ public final class MediaRouter2 { mImpl.transfer( controller.getRoutingSessionInfo(), route, - android.os.Process.myUserHandle(), + Process.myUserHandle(), mContext.getPackageName()); } @@ -883,7 +889,7 @@ public final class MediaRouter2 { newRoutes.stream().map(MediaRoute2Info::getId).collect(Collectors.toSet()); for (MediaRoute2Info route : newRoutes) { - MediaRoute2Info prevRoute = mPreviousRoutes.get(route.getId()); + MediaRoute2Info prevRoute = mPreviousFilteredRoutes.get(route.getId()); if (prevRoute == null) { addedRoutes.add(route); } else if (!prevRoute.equals(route)) { @@ -891,21 +897,21 @@ public final class MediaRouter2 { } } - for (int i = 0; i < mPreviousRoutes.size(); i++) { - if (!newRouteIds.contains(mPreviousRoutes.keyAt(i))) { - removedRoutes.add(mPreviousRoutes.valueAt(i)); + for (int i = 0; i < mPreviousFilteredRoutes.size(); i++) { + if (!newRouteIds.contains(mPreviousFilteredRoutes.keyAt(i))) { + removedRoutes.add(mPreviousFilteredRoutes.valueAt(i)); } } // update previous routes for (MediaRoute2Info route : removedRoutes) { - mPreviousRoutes.remove(route.getId()); + mPreviousFilteredRoutes.remove(route.getId()); } for (MediaRoute2Info route : addedRoutes) { - mPreviousRoutes.put(route.getId(), route); + mPreviousFilteredRoutes.put(route.getId(), route); } for (MediaRoute2Info route : changedRoutes) { - mPreviousRoutes.put(route.getId(), route); + mPreviousFilteredRoutes.put(route.getId(), route); } if (!addedRoutes.isEmpty()) { @@ -924,6 +930,27 @@ public final class MediaRouter2 { } } + void dispatchControllerUpdatedIfNeededOnHandler(Map<String, MediaRoute2Info> routesMap) { + List<RoutingController> controllers = getControllers(); + for (RoutingController controller : controllers) { + + for (String selectedRoute : controller.getRoutingSessionInfo().getSelectedRoutes()) { + if (routesMap.containsKey(selectedRoute) + && mPreviousUnfilteredRoutes.containsKey(selectedRoute)) { + MediaRoute2Info currentRoute = routesMap.get(selectedRoute); + MediaRoute2Info oldRoute = mPreviousUnfilteredRoutes.get(selectedRoute); + if (!currentRoute.equals(oldRoute)) { + notifyControllerUpdated(controller); + break; + } + } + } + } + + mPreviousUnfilteredRoutes.clear(); + mPreviousUnfilteredRoutes.putAll(routesMap); + } + void updateRoutesOnHandler(List<MediaRoute2Info> newRoutes) { synchronized (mLock) { mRoutes.clear(); @@ -945,6 +972,11 @@ public final class MediaRouter2 { MediaRouter2::dispatchFilteredRoutesUpdatedOnHandler, this, mFilteredRoutes)); + mHandler.sendMessage( + obtainMessage( + MediaRouter2::dispatchControllerUpdatedIfNeededOnHandler, + this, + new HashMap<>(mRoutes))); } /** @@ -1528,7 +1560,7 @@ public final class MediaRouter2 { UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle(); String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName(); - return Objects.equals(android.os.Process.myUserHandle(), transferInitiatorUserHandle) + return Objects.equals(Process.myUserHandle(), transferInitiatorUserHandle) && Objects.equals(mContext.getPackageName(), transferInitiatorPackageName); } @@ -2153,18 +2185,19 @@ public final class MediaRouter2 { mClientUser = user; mClientPackageName = clientPackageName; mClient = new Client(); + mDiscoveryPreference = RouteDiscoveryPreference.EMPTY; + } + public void registerProxyRouter() { try { mMediaRouterService.registerProxyRouter( mClient, - context.getApplicationContext().getPackageName(), - clientPackageName, - user); + mContext.getApplicationContext().getPackageName(), + mClientPackageName, + mClientUser); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } - - mDiscoveryPreference = RouteDiscoveryPreference.EMPTY; } @Override @@ -2294,11 +2327,7 @@ public final class MediaRouter2 { List<RoutingSessionInfo> sessionInfos = getRoutingSessions(); RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1); - transfer( - targetSession, - route, - android.os.Process.myUserHandle(), - mContext.getPackageName()); + transfer(targetSession, route, Process.myUserHandle(), mContext.getPackageName()); } @Override @@ -3165,8 +3194,12 @@ public final class MediaRouter2 { return; } - requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE, - android.os.Process.myUserHandle(), mContext.getPackageName()); + requestCreateController( + controller, + route, + MANAGER_REQUEST_ID_NONE, + Process.myUserHandle(), + mContext.getPackageName()); } @Override diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl index a7ec6c692416..8ce1b6d5264d 100644 --- a/media/java/android/media/projection/IMediaProjectionManager.aidl +++ b/media/java/android/media/projection/IMediaProjectionManager.aidl @@ -37,31 +37,41 @@ interface IMediaProjectionManager { const String EXTRA_PACKAGE_REUSING_GRANTED_CONSENT = "extra_media_projection_package_reusing_consent"; + /** + * Returns whether a combination of process UID and package has the projection permission. + * + * @param processUid the process UID as returned by {@link android.os.Process.myUid()}. + */ @UnsupportedAppUsage - boolean hasProjectionPermission(int uid, String packageName); + boolean hasProjectionPermission(int processUid, String packageName); /** * Returns a new {@link IMediaProjection} instance associated with the given package. + * + * @param processUid the process UID as returned by {@link android.os.Process.myUid()}. */ @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - IMediaProjection createProjection(int uid, String packageName, int type, + IMediaProjection createProjection(int processUid, String packageName, int type, boolean permanentGrant); /** * Returns the current {@link IMediaProjection} instance associated with the given - * package, or {@code null} if it is not possible to re-use the current projection. + * package and process UID, or {@code null} if it is not possible to re-use the current + * projection. * * <p>Should only be invoked when the user has reviewed consent for a re-used projection token. * Requires that there is a prior session waiting for the user to review consent, and the given * package details match those on the current projection. * * @see {@link #isCurrentProjection} + * + * @param processUid the process UID as returned by {@link android.os.Process.myUid()}. */ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - IMediaProjection getProjection(int uid, String packageName); + IMediaProjection getProjection(int processUid, String packageName); /** * Returns {@code true} if the given {@link IMediaProjection} corresponds to the current @@ -162,8 +172,8 @@ interface IMediaProjectionManager { * * <p>Only used for emitting atoms. * - * @param hostUid The uid of the process requesting consent to capture, may be an app or - * SystemUI. + * @param hostProcessUid The uid of the process requesting consent to capture, may be an + * app or SystemUI. * @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED. * Indicates the entry point for requesting the permission. Must be * a valid state defined @@ -172,49 +182,49 @@ interface IMediaProjectionManager { @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - oneway void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource); + oneway void notifyPermissionRequestInitiated(int hostProcessUid, int sessionCreationSource); /** * Notifies system server that the permission request was displayed. * * <p>Only used for emitting atoms. * - * @param hostUid The uid of the process requesting consent to capture, may be an app or - * SystemUI. + * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or + * SystemUI. */ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - oneway void notifyPermissionRequestDisplayed(int hostUid); + oneway void notifyPermissionRequestDisplayed(int hostProcessUid); /** * Notifies system server that the permission request was cancelled. * * <p>Only used for emitting atoms. * - * @param hostUid The uid of the process requesting consent to capture, may be an app or - * SystemUI. + * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or + * SystemUI. */ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - oneway void notifyPermissionRequestCancelled(int hostUid); + oneway void notifyPermissionRequestCancelled(int hostProcessUid); /** * Notifies system server that the app selector was displayed. * * <p>Only used for emitting atoms. * - * @param hostUid The uid of the process requesting consent to capture, may be an app or - * SystemUI. + * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or + * SystemUI. */ @EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - oneway void notifyAppSelectorDisplayed(int hostUid); + oneway void notifyAppSelectorDisplayed(int hostProcessUid); @EnforcePermission("MANAGE_MEDIA_PROJECTION") @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest" + ".permission.MANAGE_MEDIA_PROJECTION)") - void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode); + void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode); } diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java index 262f5f198c22..096e8adf2f68 100644 --- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java +++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java @@ -50,8 +50,16 @@ public final class BluetoothMidiDevice { private static final String TAG = "BluetoothMidiDevice"; private static final boolean DEBUG = false; - private static final int DEFAULT_PACKET_SIZE = 20; - private static final int MAX_PACKET_SIZE = 512; + // Bluetooth services should subtract 5 bytes from the MTU for headers. + private static final int HEADER_SIZE = 5; + // Min MTU size for BLE + private static final int MIN_L2CAP_MTU = 23; + // 23 (min L2CAP MTU) - 5 (header size) + private static final int DEFAULT_PACKET_SIZE = MIN_L2CAP_MTU - HEADER_SIZE; + // Max MTU size on Android + private static final int MAX_ANDROID_MTU = 517; + // 517 (max Android MTU) - 5 (header size) + private static final int MAX_PACKET_SIZE = MAX_ANDROID_MTU - HEADER_SIZE; // Bluetooth MIDI Gatt service UUID private static final UUID MIDI_SERVICE = UUID.fromString( @@ -135,8 +143,8 @@ public final class BluetoothMidiDevice { // switch to receiving notifications mBluetoothGatt.readCharacteristic(characteristic); - // Request higher MTU size - if (!gatt.requestMtu(MAX_PACKET_SIZE)) { + // Request max MTU size + if (!gatt.requestMtu(MAX_ANDROID_MTU)) { Log.e(TAG, "request mtu failed"); mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE); mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE); @@ -204,8 +212,15 @@ public final class BluetoothMidiDevice { public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { Log.d(TAG, "onMtuChanged callback received. mtu: " + mtu + ", status: " + status); if (status == BluetoothGatt.GATT_SUCCESS) { - mPacketEncoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE)); - mPacketDecoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE)); + int packetSize = Math.min(mtu - HEADER_SIZE, MAX_PACKET_SIZE); + if (packetSize <= 0) { + Log.e(TAG, "onMtuChanged non-positive packet size: " + packetSize); + packetSize = DEFAULT_PACKET_SIZE; + } else if (packetSize < DEFAULT_PACKET_SIZE) { + Log.w(TAG, "onMtuChanged small packet size: " + packetSize); + } + mPacketEncoder.setMaxPacketSize(packetSize); + mPacketDecoder.setMaxPacketSize(packetSize); } else { mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE); mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE); diff --git a/nfc-extras/Android.bp b/nfc-extras/Android.bp index cb9ac6fd1d33..1f187e8eab74 100644 --- a/nfc-extras/Android.bp +++ b/nfc-extras/Android.bp @@ -23,9 +23,13 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +// TODO(b/303286040): Deprecate this API surface since this is no longer supported (see ag/443092) java_sdk_library { name: "com.android.nfc_extras", srcs: ["java/**/*.java"], + libs: [ + "framework-nfc.impl" + ], api_packages: ["com.android.nfc_extras"], dist_group: "android", } diff --git a/nfc/Android.bp b/nfc/Android.bp index bf9f47ceb0a7..5d1404a56a9e 100644 --- a/nfc/Android.bp +++ b/nfc/Android.bp @@ -10,7 +10,15 @@ package { filegroup { name: "framework-nfc-non-updatable-sources", path: "java", - srcs: [], + srcs: [ + "java/android/nfc/NfcServiceManager.java", + "java/android/nfc/cardemulation/ApduServiceInfo.aidl", + "java/android/nfc/cardemulation/ApduServiceInfo.java", + "java/android/nfc/cardemulation/NfcFServiceInfo.aidl", + "java/android/nfc/cardemulation/NfcFServiceInfo.java", + "java/android/nfc/cardemulation/AidGroup.aidl", + "java/android/nfc/cardemulation/AidGroup.java", + ], } filegroup { @@ -30,10 +38,22 @@ java_sdk_library { libs: [ "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage ], + static_libs: [ + "android.nfc.flags-aconfig-java", + "android.permission.flags-aconfig-java", + ], srcs: [ ":framework-nfc-updatable-sources", + ":framework-nfc-javastream-protos", ], - defaults: ["framework-non-updatable-unbundled-defaults"], + defaults: ["framework-module-defaults"], + sdk_version: "module_current", + min_sdk_version: "34", // should be 35 (making it 34 for compiling for `-next`) + installable: true, + optimize: { + enabled: false, + }, + hostdex: true, // for hiddenapi check permitted_packages: [ "android.nfc", "com.android.nfc", @@ -41,11 +61,18 @@ java_sdk_library { hidden_api_packages: [ "com.android.nfc", ], - aidl: { - include_dirs: [ - // TODO (b/303286040): Remove these when we change to |framework-module-defaults| - "frameworks/base/nfc/java", - "frameworks/base/core/java", - ], + impl_library_visibility: [ + "//frameworks/base:__subpackages__", + "//cts/tests/tests/nfc", + "//packages/apps/Nfc:__subpackages__", + ], + jarjar_rules: ":nfc-jarjar-rules", + lint: { + strict_updatability_linting: true, }, } + +filegroup { + name: "nfc-jarjar-rules", + srcs: ["jarjar-rules.txt"], +} diff --git a/nfc/api/current.txt b/nfc/api/current.txt index d802177e249b..24c145f890c4 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -1 +1,455 @@ // Signature format: 2.0 +package android.nfc { + + public final class AvailableNfcAntenna implements android.os.Parcelable { + ctor public AvailableNfcAntenna(int, int); + method public int describeContents(); + method public int getLocationX(); + method public int getLocationY(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR; + } + + public class FormatException extends java.lang.Exception { + ctor public FormatException(); + ctor public FormatException(String); + ctor public FormatException(String, Throwable); + } + + public final class NdefMessage implements android.os.Parcelable { + ctor public NdefMessage(byte[]) throws android.nfc.FormatException; + ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...); + ctor public NdefMessage(android.nfc.NdefRecord[]); + method public int describeContents(); + method public int getByteArrayLength(); + method public android.nfc.NdefRecord[] getRecords(); + method public byte[] toByteArray(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefMessage> CREATOR; + } + + public final class NdefRecord implements android.os.Parcelable { + ctor public NdefRecord(short, byte[], byte[], byte[]); + ctor @Deprecated public NdefRecord(byte[]) throws android.nfc.FormatException; + method public static android.nfc.NdefRecord createApplicationRecord(String); + method public static android.nfc.NdefRecord createExternal(String, String, byte[]); + method public static android.nfc.NdefRecord createMime(String, byte[]); + method public static android.nfc.NdefRecord createTextRecord(String, String); + method public static android.nfc.NdefRecord createUri(android.net.Uri); + method public static android.nfc.NdefRecord createUri(String); + method public int describeContents(); + method public byte[] getId(); + method public byte[] getPayload(); + method public short getTnf(); + method public byte[] getType(); + method @Deprecated public byte[] toByteArray(); + method public String toMimeType(); + method public android.net.Uri toUri(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR; + field public static final byte[] RTD_ALTERNATIVE_CARRIER; + field public static final byte[] RTD_HANDOVER_CARRIER; + field public static final byte[] RTD_HANDOVER_REQUEST; + field public static final byte[] RTD_HANDOVER_SELECT; + field public static final byte[] RTD_SMART_POSTER; + field public static final byte[] RTD_TEXT; + field public static final byte[] RTD_URI; + field public static final short TNF_ABSOLUTE_URI = 3; // 0x3 + field public static final short TNF_EMPTY = 0; // 0x0 + field public static final short TNF_EXTERNAL_TYPE = 4; // 0x4 + field public static final short TNF_MIME_MEDIA = 2; // 0x2 + field public static final short TNF_UNCHANGED = 6; // 0x6 + field public static final short TNF_UNKNOWN = 5; // 0x5 + field public static final short TNF_WELL_KNOWN = 1; // 0x1 + } + + public final class NfcAdapter { + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean allowTransaction(); + method public void disableForegroundDispatch(android.app.Activity); + method public void disableReaderMode(android.app.Activity); + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean disallowTransaction(); + method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]); + method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); + method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); + method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo(); + method @FlaggedApi("android.nfc.enable_nfc_charging") @Nullable public android.nfc.WlcLDeviceInfo getWlcLDeviceInfo(); + method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler); + method public boolean isEnabled(); + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported(); + method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled(); + method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported(); + method public boolean isSecureNfcEnabled(); + method public boolean isSecureNfcSupported(); + method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled(); + method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity); + method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int); + field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED"; + field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; + field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED"; + field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; + field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; + field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED"; + field public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE"; + field public static final String EXTRA_AID = "android.nfc.extra.AID"; + field public static final String EXTRA_DATA = "android.nfc.extra.DATA"; + field public static final String EXTRA_ID = "android.nfc.extra.ID"; + field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; + field public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON"; + field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; + field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME"; + field public static final String EXTRA_TAG = "android.nfc.extra.TAG"; + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_DISABLE = 0; // 0x0 + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_KEEP = -1; // 0xffffffff + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_A = 1; // 0x1 + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_B = 2; // 0x2 + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_F = 4; // 0x4 + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_DISABLE = 0; // 0x0 + field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_KEEP = -1; // 0xffffffff + field public static final int FLAG_READER_NFC_A = 1; // 0x1 + field public static final int FLAG_READER_NFC_B = 2; // 0x2 + field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10 + field public static final int FLAG_READER_NFC_F = 4; // 0x4 + field public static final int FLAG_READER_NFC_V = 8; // 0x8 + field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100 + field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80 + field public static final int PREFERRED_PAYMENT_CHANGED = 2; // 0x2 + field public static final int PREFERRED_PAYMENT_LOADED = 1; // 0x1 + field public static final int PREFERRED_PAYMENT_UPDATED = 3; // 0x3 + field public static final int STATE_OFF = 1; // 0x1 + field public static final int STATE_ON = 3; // 0x3 + field public static final int STATE_TURNING_OFF = 4; // 0x4 + field public static final int STATE_TURNING_ON = 2; // 0x2 + } + + @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback { + method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent); + } + + @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback { + method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent); + } + + @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback { + method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent); + } + + public static interface NfcAdapter.OnTagRemovedListener { + method public void onTagRemoved(); + } + + public static interface NfcAdapter.ReaderCallback { + method public void onTagDiscovered(android.nfc.Tag); + } + + public final class NfcAntennaInfo implements android.os.Parcelable { + ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>); + method public int describeContents(); + method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas(); + method public int getDeviceHeight(); + method public int getDeviceWidth(); + method public boolean isDeviceFoldable(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR; + } + + public final class NfcEvent { + field public final android.nfc.NfcAdapter nfcAdapter; + field public final int peerLlcpMajorVersion; + field public final int peerLlcpMinorVersion; + } + + public final class NfcManager { + method public android.nfc.NfcAdapter getDefaultAdapter(); + } + + public final class Tag implements android.os.Parcelable { + method public int describeContents(); + method public byte[] getId(); + method public String[] getTechList(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR; + } + + public class TagLostException extends java.io.IOException { + ctor public TagLostException(); + ctor public TagLostException(String); + } + + @FlaggedApi("android.nfc.enable_nfc_charging") public final class WlcLDeviceInfo implements android.os.Parcelable { + ctor public WlcLDeviceInfo(double, double, double, int); + method public int describeContents(); + method public double getBatteryLevel(); + method public double getProductId(); + method public int getState(); + method public double getTemperature(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CONNECTED_CHARGING = 2; // 0x2 + field public static final int CONNECTED_DISCHARGING = 3; // 0x3 + field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcLDeviceInfo> CREATOR; + field public static final int DISCONNECTED = 1; // 0x1 + } + +} + +package android.nfc.cardemulation { + + public final class CardEmulation { + method public boolean categoryAllowsForegroundPreference(String); + method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService(); + method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String); + method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService(); + method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter); + method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService(); + method public int getSelectionModeForCategory(String); + method public boolean isDefaultServiceForAid(android.content.ComponentName, String); + method public boolean isDefaultServiceForCategory(android.content.ComponentName, String); + method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>); + method public boolean removeAidsForService(android.content.ComponentName, String); + method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String); + method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean); + method public boolean supportsAidPrefixRegistration(); + method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName); + method public boolean unsetPreferredService(android.app.Activity); + field @Deprecated public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; + field public static final String CATEGORY_OTHER = "other"; + field public static final String CATEGORY_PAYMENT = "payment"; + field public static final String EXTRA_CATEGORY = "category"; + field public static final String EXTRA_SERVICE_COMPONENT = "component"; + field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1 + field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2 + field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0 + } + + public abstract class HostApduService extends android.app.Service { + ctor public HostApduService(); + method public final void notifyUnhandled(); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract void onDeactivated(int); + method public abstract byte[] processCommandApdu(byte[], android.os.Bundle); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>); + method public final void sendResponseApdu(byte[]); + field public static final int DEACTIVATION_DESELECTED = 1; // 0x1 + field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0 + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA"; + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN"; + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP"; + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A' + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B' + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F' + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE"; + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X' + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O' + field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U' + field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE"; + field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service"; + } + + public abstract class HostNfcFService extends android.app.Service { + ctor public HostNfcFService(); + method public final android.os.IBinder onBind(android.content.Intent); + method public abstract void onDeactivated(int); + method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle); + method public final void sendResponsePacket(byte[]); + field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0 + field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE"; + field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service"; + } + + public final class NfcFCardEmulation { + method public boolean disableService(android.app.Activity) throws java.lang.RuntimeException; + method public boolean enableService(android.app.Activity, android.content.ComponentName) throws java.lang.RuntimeException; + method public static android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter); + method public String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException; + method public String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException; + method public boolean registerSystemCodeForService(android.content.ComponentName, String) throws java.lang.RuntimeException; + method public boolean setNfcid2ForService(android.content.ComponentName, String) throws java.lang.RuntimeException; + method public boolean unregisterSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException; + } + + public abstract class OffHostApduService extends android.app.Service { + ctor public OffHostApduService(); + field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"; + field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service"; + } + +} + +package android.nfc.tech { + + public final class IsoDep implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.IsoDep get(android.nfc.Tag); + method public byte[] getHiLayerResponse(); + method public byte[] getHistoricalBytes(); + method public int getMaxTransceiveLength(); + method public android.nfc.Tag getTag(); + method public int getTimeout(); + method public boolean isConnected(); + method public boolean isExtendedLengthApduSupported(); + method public void setTimeout(int); + method public byte[] transceive(byte[]) throws java.io.IOException; + } + + public final class MifareClassic implements android.nfc.tech.TagTechnology { + method public boolean authenticateSectorWithKeyA(int, byte[]) throws java.io.IOException; + method public boolean authenticateSectorWithKeyB(int, byte[]) throws java.io.IOException; + method public int blockToSector(int); + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public void decrement(int, int) throws java.io.IOException; + method public static android.nfc.tech.MifareClassic get(android.nfc.Tag); + method public int getBlockCount(); + method public int getBlockCountInSector(int); + method public int getMaxTransceiveLength(); + method public int getSectorCount(); + method public int getSize(); + method public android.nfc.Tag getTag(); + method public int getTimeout(); + method public int getType(); + method public void increment(int, int) throws java.io.IOException; + method public boolean isConnected(); + method public byte[] readBlock(int) throws java.io.IOException; + method public void restore(int) throws java.io.IOException; + method public int sectorToBlock(int); + method public void setTimeout(int); + method public byte[] transceive(byte[]) throws java.io.IOException; + method public void transfer(int) throws java.io.IOException; + method public void writeBlock(int, byte[]) throws java.io.IOException; + field public static final int BLOCK_SIZE = 16; // 0x10 + field public static final byte[] KEY_DEFAULT; + field public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY; + field public static final byte[] KEY_NFC_FORUM; + field public static final int SIZE_1K = 1024; // 0x400 + field public static final int SIZE_2K = 2048; // 0x800 + field public static final int SIZE_4K = 4096; // 0x1000 + field public static final int SIZE_MINI = 320; // 0x140 + field public static final int TYPE_CLASSIC = 0; // 0x0 + field public static final int TYPE_PLUS = 1; // 0x1 + field public static final int TYPE_PRO = 2; // 0x2 + field public static final int TYPE_UNKNOWN = -1; // 0xffffffff + } + + public final class MifareUltralight implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag); + method public int getMaxTransceiveLength(); + method public android.nfc.Tag getTag(); + method public int getTimeout(); + method public int getType(); + method public boolean isConnected(); + method public byte[] readPages(int) throws java.io.IOException; + method public void setTimeout(int); + method public byte[] transceive(byte[]) throws java.io.IOException; + method public void writePage(int, byte[]) throws java.io.IOException; + field public static final int PAGE_SIZE = 4; // 0x4 + field public static final int TYPE_ULTRALIGHT = 1; // 0x1 + field public static final int TYPE_ULTRALIGHT_C = 2; // 0x2 + field public static final int TYPE_UNKNOWN = -1; // 0xffffffff + } + + public final class Ndef implements android.nfc.tech.TagTechnology { + method public boolean canMakeReadOnly(); + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.Ndef get(android.nfc.Tag); + method public android.nfc.NdefMessage getCachedNdefMessage(); + method public int getMaxSize(); + method public android.nfc.NdefMessage getNdefMessage() throws android.nfc.FormatException, java.io.IOException; + method public android.nfc.Tag getTag(); + method public String getType(); + method public boolean isConnected(); + method public boolean isWritable(); + method public boolean makeReadOnly() throws java.io.IOException; + method public void writeNdefMessage(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; + field public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic"; + field public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1"; + field public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2"; + field public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3"; + field public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4"; + } + + public final class NdefFormatable implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public void format(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; + method public void formatReadOnly(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException; + method public static android.nfc.tech.NdefFormatable get(android.nfc.Tag); + method public android.nfc.Tag getTag(); + method public boolean isConnected(); + } + + public final class NfcA implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.NfcA get(android.nfc.Tag); + method public byte[] getAtqa(); + method public int getMaxTransceiveLength(); + method public short getSak(); + method public android.nfc.Tag getTag(); + method public int getTimeout(); + method public boolean isConnected(); + method public void setTimeout(int); + method public byte[] transceive(byte[]) throws java.io.IOException; + } + + public final class NfcB implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.NfcB get(android.nfc.Tag); + method public byte[] getApplicationData(); + method public int getMaxTransceiveLength(); + method public byte[] getProtocolInfo(); + method public android.nfc.Tag getTag(); + method public boolean isConnected(); + method public byte[] transceive(byte[]) throws java.io.IOException; + } + + public final class NfcBarcode implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.NfcBarcode get(android.nfc.Tag); + method public byte[] getBarcode(); + method public android.nfc.Tag getTag(); + method public int getType(); + method public boolean isConnected(); + field public static final int TYPE_KOVIO = 1; // 0x1 + field public static final int TYPE_UNKNOWN = -1; // 0xffffffff + } + + public final class NfcF implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.NfcF get(android.nfc.Tag); + method public byte[] getManufacturer(); + method public int getMaxTransceiveLength(); + method public byte[] getSystemCode(); + method public android.nfc.Tag getTag(); + method public int getTimeout(); + method public boolean isConnected(); + method public void setTimeout(int); + method public byte[] transceive(byte[]) throws java.io.IOException; + } + + public final class NfcV implements android.nfc.tech.TagTechnology { + method public void close() throws java.io.IOException; + method public void connect() throws java.io.IOException; + method public static android.nfc.tech.NfcV get(android.nfc.Tag); + method public byte getDsfId(); + method public int getMaxTransceiveLength(); + method public byte getResponseFlags(); + method public android.nfc.Tag getTag(); + method public boolean isConnected(); + method public byte[] transceive(byte[]) throws java.io.IOException; + } + + public interface TagTechnology extends java.io.Closeable { + method public void connect() throws java.io.IOException; + method public android.nfc.Tag getTag(); + method public boolean isConnected(); + } + +} + diff --git a/nfc/api/lint-baseline.txt b/nfc/api/lint-baseline.txt new file mode 100644 index 000000000000..ef9aab6e7641 --- /dev/null +++ b/nfc/api/lint-baseline.txt @@ -0,0 +1,95 @@ +// Baseline format: 1.0 +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior + + +MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent): + Missing nullability on method `onBind` return +MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent) parameter #0: + Missing nullability on parameter `intent` in method `onBind` + + +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission diff --git a/nfc/api/module-lib-current.txt b/nfc/api/module-lib-current.txt index d802177e249b..5ebe91111ec0 100644 --- a/nfc/api/module-lib-current.txt +++ b/nfc/api/module-lib-current.txt @@ -1 +1,10 @@ // Signature format: 2.0 +package android.nfc { + + public class NfcFrameworkInitializer { + method public static void registerServiceWrappers(); + method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager); + } + +} + diff --git a/nfc/api/module-lib-lint-baseline.txt b/nfc/api/module-lib-lint-baseline.txt new file mode 100644 index 000000000000..f7f8ee3ddda5 --- /dev/null +++ b/nfc/api/module-lib-lint-baseline.txt @@ -0,0 +1,93 @@ +// Baseline format: 1.0 +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior + +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission + +SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) diff --git a/nfc/api/removed.txt b/nfc/api/removed.txt index d802177e249b..fb82b5ddbb21 100644 --- a/nfc/api/removed.txt +++ b/nfc/api/removed.txt @@ -1 +1,17 @@ // Signature format: 2.0 +package android.nfc { + + public final class NfcAdapter { + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void disableForegroundNdefPush(android.app.Activity); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public boolean invokeBeam(android.app.Activity); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public boolean isNdefPushEnabled(); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setBeamPushUris(android.net.Uri[], android.app.Activity); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...); + method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...); + } + +} + diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index d802177e249b..40672a1adc15 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -1 +1,53 @@ // Signature format: 2.0 +package android.nfc { + + public final class NfcAdapter { + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); + method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); + method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableWlc(boolean); + method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState(); + method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int); + method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn(); + method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported(); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported(); + method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener); + method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler); + method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean); + method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean); + method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener); + method @FlaggedApi("android.nfc.enable_nfc_charging") public void unregisterWlcStateListener(@NonNull android.nfc.NfcAdapter.WlcStateListener); + field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; + field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff + field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0 + field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe + } + + public static interface NfcAdapter.ControllerAlwaysOnListener { + method public void onControllerAlwaysOnChanged(boolean); + } + + public static interface NfcAdapter.NfcUnlockHandler { + method public boolean onUnlockAttempted(android.nfc.Tag); + } + + @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener { + method public void onWlcStateChanged(@NonNull android.nfc.WlcLDeviceInfo); + } + +} + +package android.nfc.cardemulation { + + public final class CardEmulation { + method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public android.nfc.cardemulation.ApduServiceInfo getPreferredPaymentService(); + method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int); + } + +} + diff --git a/nfc/api/system-lint-baseline.txt b/nfc/api/system-lint-baseline.txt new file mode 100644 index 000000000000..761c8e63df81 --- /dev/null +++ b/nfc/api/system-lint-baseline.txt @@ -0,0 +1,105 @@ +// Baseline format: 1.0 +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED: + Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED: + Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior +BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED: + Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior + + +MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent): + Missing nullability on method `onBind` return +MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent) parameter #0: + Missing nullability on parameter `intent` in method `onBind` + + +RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity): + Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]): + Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String): + Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String): + Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String): + Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]): + Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]): + Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int): + Method 'decrement' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int): + Method 'increment' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int): + Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#restore(int): + Method 'restore' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#transfer(int): + Method 'transfer' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]): + Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int): + Method 'readPages' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]): + Method 'writePage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#getNdefMessage(): + Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#isWritable(): + Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#makeReadOnly(): + Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage): + Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage): + Method 'format' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage): + Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#getTimeout(): + Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#setTimeout(int): + Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]): + Method 'transceive' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#close(): + Method 'close' documentation mentions permissions without declaring @RequiresPermission +RequiresPermission: android.nfc.tech.TagTechnology#connect(): + Method 'connect' documentation mentions permissions without declaring @RequiresPermission + +SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle): + SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions +SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler): + SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions + +SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC: + Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) diff --git a/nfc/api/system-removed.txt b/nfc/api/system-removed.txt index d802177e249b..c6eaa57b6b06 100644 --- a/nfc/api/system-removed.txt +++ b/nfc/api/system-removed.txt @@ -1 +1,12 @@ // Signature format: 2.0 +package android.nfc { + + public final class NfcAdapter { + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush(); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush(); + method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int); + field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1 + } + +} + diff --git a/nfc/jarjar-rules.txt b/nfc/jarjar-rules.txt new file mode 100644 index 000000000000..4cd652d6af7f --- /dev/null +++ b/nfc/jarjar-rules.txt @@ -0,0 +1,38 @@ +# Used by framework-nfc for proto debug dumping +rule android.app.PendingIntentProto* com.android.nfc.x.@0 +rule android.content.ComponentNameProto* com.android.nfc.x.@0 +rule android.content.IntentProto* com.android.nfc.x.@0 +rule android.content.IntentFilterProto* com.android.nfc.x.@0 +rule android.content.AuthorityEntryProto* com.android.nfc.x.@0 +rule android.nfc.cardemulation.AidGroupProto* com.android.nfc.x.@0 +rule android.nfc.cardemulation.ApduServiceInfoProto* com.android.nfc.x.@0 +rule android.nfc.cardemulation.NfcFServiceInfoProto* com.android.nfc.x.@0 +rule android.nfc.NdefMessageProto* com.android.nfc.x.@0 +rule android.nfc.NdefRecordProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.CardEmulationManagerProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.RegisteredServicesCacheProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.RegisteredNfcFServicesCacheProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.PreferredServicesProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.EnabledNfcFServicesProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.RegisteredAidCacheProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.AidRoutingManagerProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.RegisteredT3tIdentifiersCacheProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.SystemCodeRoutingManagerProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.HostEmulationManagerProto* com.android.nfc.x.@0 +rule com.android.nfc.cardemulation.HostNfcFEmulationManagerProto* com.android.nfc.x.@0 +rule com.android.nfc.NfcServiceDumpProto* com.android.nfc.x.@0 +rule com.android.nfc.DiscoveryParamsProto* com.android.nfc.x.@0 +rule com.android.nfc.NfcDispatcherProto* com.android.nfc.x.@0 +rule android.os.PersistableBundleProto* com.android.nfc.x.@0 + +# Used by framework-nfc for reading trunk stable flags +rule android.nfc.FakeFeatureFlagsImpl* com.android.nfc.x.@0 +rule android.nfc.FeatureFlags* com.android.nfc.x.@0 +rule android.nfc.Flags* com.android.nfc.x.@0 +rule android.permission.flags.** com.android.nfc.x.@0 + +# Used by framework-nfc for misc utilities +rule android.os.PatternMatcher* com.android.nfc.x.@0 + +rule com.android.incident.Privacy* com.android.nfc.x.@0 +rule com.android.incident.PrivacyFlags* com.android.nfc.x.@0 diff --git a/core/java/android/nfc/ApduList.aidl b/nfc/java/android/nfc/ApduList.aidl index f6236b2bfb3b..f6236b2bfb3b 100644 --- a/core/java/android/nfc/ApduList.aidl +++ b/nfc/java/android/nfc/ApduList.aidl diff --git a/core/java/android/nfc/ApduList.java b/nfc/java/android/nfc/ApduList.java index 027141d99c30..027141d99c30 100644 --- a/core/java/android/nfc/ApduList.java +++ b/nfc/java/android/nfc/ApduList.java diff --git a/core/java/android/nfc/AvailableNfcAntenna.aidl b/nfc/java/android/nfc/AvailableNfcAntenna.aidl index 9d06e2d7d5eb..9d06e2d7d5eb 100644 --- a/core/java/android/nfc/AvailableNfcAntenna.aidl +++ b/nfc/java/android/nfc/AvailableNfcAntenna.aidl diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java index 6e6512a04971..6e6512a04971 100644 --- a/core/java/android/nfc/AvailableNfcAntenna.java +++ b/nfc/java/android/nfc/AvailableNfcAntenna.java diff --git a/core/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java index f76833063605..f76833063605 100644 --- a/core/java/android/nfc/Constants.java +++ b/nfc/java/android/nfc/Constants.java diff --git a/core/java/android/nfc/ErrorCodes.java b/nfc/java/android/nfc/ErrorCodes.java index d2c81cd27d90..d2c81cd27d90 100644 --- a/core/java/android/nfc/ErrorCodes.java +++ b/nfc/java/android/nfc/ErrorCodes.java diff --git a/core/java/android/nfc/FormatException.java b/nfc/java/android/nfc/FormatException.java index a57de1e0e21a..a57de1e0e21a 100644 --- a/core/java/android/nfc/FormatException.java +++ b/nfc/java/android/nfc/FormatException.java diff --git a/core/java/android/nfc/IAppCallback.aidl b/nfc/java/android/nfc/IAppCallback.aidl index b06bf06d5197..b06bf06d5197 100644 --- a/core/java/android/nfc/IAppCallback.aidl +++ b/nfc/java/android/nfc/IAppCallback.aidl diff --git a/core/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl index 286cf2890eea..286cf2890eea 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/nfc/java/android/nfc/INfcAdapterExtras.aidl index cde57c58ca1f..cde57c58ca1f 100644 --- a/core/java/android/nfc/INfcAdapterExtras.aidl +++ b/nfc/java/android/nfc/INfcAdapterExtras.aidl diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index f4b46046bc3e..f4b46046bc3e 100644 --- a/core/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl diff --git a/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl index 1bb7680d2fed..1bb7680d2fed 100644 --- a/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl +++ b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl diff --git a/core/java/android/nfc/INfcDta.aidl b/nfc/java/android/nfc/INfcDta.aidl index 4cc59271362b..4cc59271362b 100644 --- a/core/java/android/nfc/INfcDta.aidl +++ b/nfc/java/android/nfc/INfcDta.aidl diff --git a/core/java/android/nfc/INfcFCardEmulation.aidl b/nfc/java/android/nfc/INfcFCardEmulation.aidl index 124bfac4f0d0..124bfac4f0d0 100644 --- a/core/java/android/nfc/INfcFCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcFCardEmulation.aidl diff --git a/core/java/android/nfc/INfcTag.aidl b/nfc/java/android/nfc/INfcTag.aidl index 170df71385bb..170df71385bb 100644 --- a/core/java/android/nfc/INfcTag.aidl +++ b/nfc/java/android/nfc/INfcTag.aidl diff --git a/core/java/android/nfc/INfcUnlockHandler.aidl b/nfc/java/android/nfc/INfcUnlockHandler.aidl index e1cace987dc3..e1cace987dc3 100644 --- a/core/java/android/nfc/INfcUnlockHandler.aidl +++ b/nfc/java/android/nfc/INfcUnlockHandler.aidl diff --git a/core/java/android/nfc/INfcWlcStateListener.aidl b/nfc/java/android/nfc/INfcWlcStateListener.aidl index c2b7075bc6e4..c2b7075bc6e4 100644 --- a/core/java/android/nfc/INfcWlcStateListener.aidl +++ b/nfc/java/android/nfc/INfcWlcStateListener.aidl diff --git a/core/java/android/nfc/ITagRemovedCallback.aidl b/nfc/java/android/nfc/ITagRemovedCallback.aidl index 2a06ff314b22..2a06ff314b22 100644 --- a/core/java/android/nfc/ITagRemovedCallback.aidl +++ b/nfc/java/android/nfc/ITagRemovedCallback.aidl diff --git a/core/java/android/nfc/NdefMessage.aidl b/nfc/java/android/nfc/NdefMessage.aidl index 378b9d05b385..378b9d05b385 100644 --- a/core/java/android/nfc/NdefMessage.aidl +++ b/nfc/java/android/nfc/NdefMessage.aidl diff --git a/core/java/android/nfc/NdefMessage.java b/nfc/java/android/nfc/NdefMessage.java index 553f6c01b016..553f6c01b016 100644 --- a/core/java/android/nfc/NdefMessage.java +++ b/nfc/java/android/nfc/NdefMessage.java diff --git a/core/java/android/nfc/NdefRecord.aidl b/nfc/java/android/nfc/NdefRecord.aidl index 10f89d0936e4..10f89d0936e4 100644 --- a/core/java/android/nfc/NdefRecord.aidl +++ b/nfc/java/android/nfc/NdefRecord.aidl diff --git a/core/java/android/nfc/NdefRecord.java b/nfc/java/android/nfc/NdefRecord.java index 7bf4355d5b35..7bf4355d5b35 100644 --- a/core/java/android/nfc/NdefRecord.java +++ b/nfc/java/android/nfc/NdefRecord.java diff --git a/core/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java index f03fc0af86b3..f03fc0af86b3 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/nfc/java/android/nfc/NfcActivityManager.java diff --git a/core/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index 8219d2f873de..8219d2f873de 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java diff --git a/core/java/android/nfc/NfcAntennaInfo.aidl b/nfc/java/android/nfc/NfcAntennaInfo.aidl index d5e79fc37282..d5e79fc37282 100644 --- a/core/java/android/nfc/NfcAntennaInfo.aidl +++ b/nfc/java/android/nfc/NfcAntennaInfo.aidl diff --git a/core/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java index b002ca21e8e3..b002ca21e8e3 100644 --- a/core/java/android/nfc/NfcAntennaInfo.java +++ b/nfc/java/android/nfc/NfcAntennaInfo.java diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java index 6ae58fd38cbe..6ae58fd38cbe 100644 --- a/core/java/android/nfc/NfcControllerAlwaysOnListener.java +++ b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java diff --git a/core/java/android/nfc/NfcEvent.java b/nfc/java/android/nfc/NfcEvent.java index aff4f52f2bab..aff4f52f2bab 100644 --- a/core/java/android/nfc/NfcEvent.java +++ b/nfc/java/android/nfc/NfcEvent.java diff --git a/core/java/android/nfc/NfcFrameworkInitializer.java b/nfc/java/android/nfc/NfcFrameworkInitializer.java index 1ab8a1ebd72c..1ab8a1ebd72c 100644 --- a/core/java/android/nfc/NfcFrameworkInitializer.java +++ b/nfc/java/android/nfc/NfcFrameworkInitializer.java diff --git a/core/java/android/nfc/NfcManager.java b/nfc/java/android/nfc/NfcManager.java index 644e3122774b..644e3122774b 100644 --- a/core/java/android/nfc/NfcManager.java +++ b/nfc/java/android/nfc/NfcManager.java diff --git a/core/java/android/nfc/NfcServiceManager.java b/nfc/java/android/nfc/NfcServiceManager.java index 5582f1154cad..5582f1154cad 100644 --- a/core/java/android/nfc/NfcServiceManager.java +++ b/nfc/java/android/nfc/NfcServiceManager.java diff --git a/core/java/android/nfc/NfcWlcStateListener.java b/nfc/java/android/nfc/NfcWlcStateListener.java index 8d793101f41f..8d793101f41f 100644 --- a/core/java/android/nfc/NfcWlcStateListener.java +++ b/nfc/java/android/nfc/NfcWlcStateListener.java diff --git a/core/java/android/nfc/Tag.aidl b/nfc/java/android/nfc/Tag.aidl index 312261ebe76d..312261ebe76d 100644 --- a/core/java/android/nfc/Tag.aidl +++ b/nfc/java/android/nfc/Tag.aidl diff --git a/core/java/android/nfc/Tag.java b/nfc/java/android/nfc/Tag.java index 500038f14d9d..500038f14d9d 100644 --- a/core/java/android/nfc/Tag.java +++ b/nfc/java/android/nfc/Tag.java diff --git a/core/java/android/nfc/TagLostException.java b/nfc/java/android/nfc/TagLostException.java index 1981d7c0c6e0..1981d7c0c6e0 100644 --- a/core/java/android/nfc/TagLostException.java +++ b/nfc/java/android/nfc/TagLostException.java diff --git a/core/java/android/nfc/TechListParcel.aidl b/nfc/java/android/nfc/TechListParcel.aidl index 92e646f220f0..92e646f220f0 100644 --- a/core/java/android/nfc/TechListParcel.aidl +++ b/nfc/java/android/nfc/TechListParcel.aidl diff --git a/core/java/android/nfc/TechListParcel.java b/nfc/java/android/nfc/TechListParcel.java index 9f01559bd344..9f01559bd344 100644 --- a/core/java/android/nfc/TechListParcel.java +++ b/nfc/java/android/nfc/TechListParcel.java diff --git a/core/java/android/nfc/TransceiveResult.aidl b/nfc/java/android/nfc/TransceiveResult.aidl index 98f92ee03eef..98f92ee03eef 100644 --- a/core/java/android/nfc/TransceiveResult.aidl +++ b/nfc/java/android/nfc/TransceiveResult.aidl diff --git a/core/java/android/nfc/TransceiveResult.java b/nfc/java/android/nfc/TransceiveResult.java index 7992094e6ba1..7992094e6ba1 100644 --- a/core/java/android/nfc/TransceiveResult.java +++ b/nfc/java/android/nfc/TransceiveResult.java diff --git a/core/java/android/nfc/WlcLDeviceInfo.aidl b/nfc/java/android/nfc/WlcLDeviceInfo.aidl index 33143fe81162..33143fe81162 100644 --- a/core/java/android/nfc/WlcLDeviceInfo.aidl +++ b/nfc/java/android/nfc/WlcLDeviceInfo.aidl diff --git a/core/java/android/nfc/WlcLDeviceInfo.java b/nfc/java/android/nfc/WlcLDeviceInfo.java index 016431e90d8e..016431e90d8e 100644 --- a/core/java/android/nfc/WlcLDeviceInfo.java +++ b/nfc/java/android/nfc/WlcLDeviceInfo.java diff --git a/core/java/android/nfc/cardemulation/AidGroup.aidl b/nfc/java/android/nfc/cardemulation/AidGroup.aidl index 56d6fa559677..56d6fa559677 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.aidl +++ b/nfc/java/android/nfc/cardemulation/AidGroup.aidl diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/nfc/java/android/nfc/cardemulation/AidGroup.java index ae3e333051d7..ae3e333051d7 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/nfc/java/android/nfc/cardemulation/AidGroup.java diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.aidl index a62fdd6a6c5c..a62fdd6a6c5c 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.aidl diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java index 41dee3ab035c..41dee3ab035c 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index ad86d70db967..81eab71fe080 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -69,7 +69,12 @@ public final class CardEmulation { * specified in {@link #EXTRA_CATEGORY}. There is an optional * extra field using {@link Intent#EXTRA_USER} to specify * the {@link UserHandle} of the user that owns the app. + * + * @deprecated Please use {@link android.app.role.RoleManager#createRequestRoleIntent(String)} + * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter + * and {@link Activity#startActivityForResult(Intent, int)} instead. */ + @Deprecated @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; @@ -1084,4 +1089,32 @@ public final class CardEmulation { sService = adapter.getCardEmulationService(); } + /** + * Returns the {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT} for the given user. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) + @FlaggedApi(android.permission.flags.Flags.FLAG_WALLET_ROLE_ENABLED) + @Nullable + public ApduServiceInfo getPreferredPaymentService() { + try { + return sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return null; + } + try { + return sService.getPreferredPaymentService(mContext.getUser().getIdentifier()); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return null; + } + } + } + } diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java index 7cd2533a7dbf..7cd2533a7dbf 100644 --- a/core/java/android/nfc/cardemulation/HostApduService.java +++ b/nfc/java/android/nfc/cardemulation/HostApduService.java diff --git a/core/java/android/nfc/cardemulation/HostNfcFService.java b/nfc/java/android/nfc/cardemulation/HostNfcFService.java index 65b5ca77de62..65b5ca77de62 100644 --- a/core/java/android/nfc/cardemulation/HostNfcFService.java +++ b/nfc/java/android/nfc/cardemulation/HostNfcFService.java diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java index 48bbf5b61052..48bbf5b61052 100644 --- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.aidl index 56b98ebd90fa..56b98ebd90fa 100644 --- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl +++ b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.aidl diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java index 33bc16978721..33bc16978721 100644 --- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java diff --git a/core/java/android/nfc/OWNERS b/nfc/java/android/nfc/cardemulation/OWNERS index 35e9713f5715..35e9713f5715 100644 --- a/core/java/android/nfc/OWNERS +++ b/nfc/java/android/nfc/cardemulation/OWNERS diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/nfc/java/android/nfc/cardemulation/OffHostApduService.java index 2286e8476d94..2286e8476d94 100644 --- a/core/java/android/nfc/cardemulation/OffHostApduService.java +++ b/nfc/java/android/nfc/cardemulation/OffHostApduService.java diff --git a/core/java/android/nfc/cardemulation/Utils.java b/nfc/java/android/nfc/cardemulation/Utils.java index 202e1cfb48f6..202e1cfb48f6 100644 --- a/core/java/android/nfc/cardemulation/Utils.java +++ b/nfc/java/android/nfc/cardemulation/Utils.java diff --git a/core/java/android/nfc/dta/NfcDta.java b/nfc/java/android/nfc/dta/NfcDta.java index 88016623434d..88016623434d 100644 --- a/core/java/android/nfc/dta/NfcDta.java +++ b/nfc/java/android/nfc/dta/NfcDta.java diff --git a/core/java/android/nfc/cardemulation/OWNERS b/nfc/java/android/nfc/dta/OWNERS index 35e9713f5715..35e9713f5715 100644 --- a/core/java/android/nfc/cardemulation/OWNERS +++ b/nfc/java/android/nfc/dta/OWNERS diff --git a/core/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig index 01a45708fddf..01a45708fddf 100644 --- a/core/java/android/nfc/flags.aconfig +++ b/nfc/java/android/nfc/flags.aconfig diff --git a/core/java/android/nfc/package.html b/nfc/java/android/nfc/package.html index 55c1d1650aa9..55c1d1650aa9 100644 --- a/core/java/android/nfc/package.html +++ b/nfc/java/android/nfc/package.html diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/nfc/java/android/nfc/tech/BasicTagTechnology.java index ae468fead7a2..ae468fead7a2 100644 --- a/core/java/android/nfc/tech/BasicTagTechnology.java +++ b/nfc/java/android/nfc/tech/BasicTagTechnology.java diff --git a/core/java/android/nfc/tech/IsoDep.java b/nfc/java/android/nfc/tech/IsoDep.java index 0ba0c5a8d13b..0ba0c5a8d13b 100644 --- a/core/java/android/nfc/tech/IsoDep.java +++ b/nfc/java/android/nfc/tech/IsoDep.java diff --git a/core/java/android/nfc/tech/MifareClassic.java b/nfc/java/android/nfc/tech/MifareClassic.java index 26f54e692289..26f54e692289 100644 --- a/core/java/android/nfc/tech/MifareClassic.java +++ b/nfc/java/android/nfc/tech/MifareClassic.java diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/nfc/java/android/nfc/tech/MifareUltralight.java index c0416a39ba76..c0416a39ba76 100644 --- a/core/java/android/nfc/tech/MifareUltralight.java +++ b/nfc/java/android/nfc/tech/MifareUltralight.java diff --git a/core/java/android/nfc/tech/Ndef.java b/nfc/java/android/nfc/tech/Ndef.java index 7d83f157a314..7d83f157a314 100644 --- a/core/java/android/nfc/tech/Ndef.java +++ b/nfc/java/android/nfc/tech/Ndef.java diff --git a/core/java/android/nfc/tech/NdefFormatable.java b/nfc/java/android/nfc/tech/NdefFormatable.java index 2240fe7f7d3b..2240fe7f7d3b 100644 --- a/core/java/android/nfc/tech/NdefFormatable.java +++ b/nfc/java/android/nfc/tech/NdefFormatable.java diff --git a/core/java/android/nfc/tech/NfcA.java b/nfc/java/android/nfc/tech/NfcA.java index 7e6648361670..7e6648361670 100644 --- a/core/java/android/nfc/tech/NfcA.java +++ b/nfc/java/android/nfc/tech/NfcA.java diff --git a/core/java/android/nfc/tech/NfcB.java b/nfc/java/android/nfc/tech/NfcB.java index 3ebd47f610c0..3ebd47f610c0 100644 --- a/core/java/android/nfc/tech/NfcB.java +++ b/nfc/java/android/nfc/tech/NfcB.java diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/nfc/java/android/nfc/tech/NfcBarcode.java index 421ba7827cb1..421ba7827cb1 100644 --- a/core/java/android/nfc/tech/NfcBarcode.java +++ b/nfc/java/android/nfc/tech/NfcBarcode.java diff --git a/core/java/android/nfc/tech/NfcF.java b/nfc/java/android/nfc/tech/NfcF.java index 2ccd38875f07..2ccd38875f07 100644 --- a/core/java/android/nfc/tech/NfcF.java +++ b/nfc/java/android/nfc/tech/NfcF.java diff --git a/core/java/android/nfc/tech/NfcV.java b/nfc/java/android/nfc/tech/NfcV.java index 186c63bf07fd..186c63bf07fd 100644 --- a/core/java/android/nfc/tech/NfcV.java +++ b/nfc/java/android/nfc/tech/NfcV.java diff --git a/core/java/android/nfc/dta/OWNERS b/nfc/java/android/nfc/tech/OWNERS index 35e9713f5715..35e9713f5715 100644 --- a/core/java/android/nfc/dta/OWNERS +++ b/nfc/java/android/nfc/tech/OWNERS diff --git a/core/java/android/nfc/tech/TagTechnology.java b/nfc/java/android/nfc/tech/TagTechnology.java index 839fe429b338..839fe429b338 100644 --- a/core/java/android/nfc/tech/TagTechnology.java +++ b/nfc/java/android/nfc/tech/TagTechnology.java diff --git a/core/java/android/nfc/tech/package.html b/nfc/java/android/nfc/tech/package.html index a99828f90c5b..a99828f90c5b 100644 --- a/core/java/android/nfc/tech/package.html +++ b/nfc/java/android/nfc/tech/package.html diff --git a/core/tests/nfctests/Android.bp b/nfc/tests/Android.bp index f81be494ad18..62566ee89fb8 100644 --- a/core/tests/nfctests/Android.bp +++ b/nfc/tests/Android.bp @@ -30,6 +30,7 @@ android_test { "truth", ], libs: [ + "framework-nfc.impl", "android.test.runner", ], srcs: ["src/**/*.java"], diff --git a/core/tests/nfctests/AndroidManifest.xml b/nfc/tests/AndroidManifest.xml index 99e2c34c656b..99e2c34c656b 100644 --- a/core/tests/nfctests/AndroidManifest.xml +++ b/nfc/tests/AndroidManifest.xml diff --git a/core/tests/nfctests/AndroidTest.xml b/nfc/tests/AndroidTest.xml index 490d6f5df197..490d6f5df197 100644 --- a/core/tests/nfctests/AndroidTest.xml +++ b/nfc/tests/AndroidTest.xml diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java index 48f4288d401e..48f4288d401e 100644 --- a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java +++ b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java diff --git a/core/tests/nfctests/src/android/nfc/TechListParcelTest.java b/nfc/tests/src/android/nfc/TechListParcelTest.java index a12bbbc6884b..a12bbbc6884b 100644 --- a/core/tests/nfctests/src/android/nfc/TechListParcelTest.java +++ b/nfc/tests/src/android/nfc/TechListParcelTest.java diff --git a/packages/CredentialManager/Android.bp b/packages/CredentialManager/Android.bp index 991fe41bb7f3..c292b5027f36 100644 --- a/packages/CredentialManager/Android.bp +++ b/packages/CredentialManager/Android.bp @@ -7,19 +7,14 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -android_app { - name: "CredentialManager", - defaults: ["platform_app_defaults"], - certificate: "platform", +android_library { + name: "CredentialManager-handheld", + + platform_apis: true, + srcs: ["src/**/*.kt"], resource_dirs: ["res"], - dex_preopt: { - profile_guided: true, - //TODO: b/312357299 - Update baseline profile - profile: "profile.txt.prof", - }, - static_libs: [ "CredentialManagerShared", "PlatformComposeCore", @@ -42,6 +37,23 @@ android_app { "androidx.recyclerview_recyclerview", "kotlinx-coroutines-core", ], +} + +android_app { + name: "CredentialManager", + defaults: ["platform_app_defaults"], + certificate: "platform", + + dex_preopt: { + profile_guided: true, + //TODO: b/312357299 - Update baseline profile + profile: "profile.txt.prof", + }, + + // Do not add new dependencies here. Add to CredentialManager-handheld instead. + static_libs: [ + "CredentialManager-handheld", + ], platform_apis: true, privileged: true, diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml index 2f0c83b6556a..5becc86927d2 100644 --- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml +++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - ~ Copyright (C) 2023 The Android Open Source Project + ~ Copyright (C) 2024 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -23,8 +23,8 @@ android:shape="rectangle" android:top="1dp"> <shape> - <corners android:radius="28dp" /> - <solid android:color="@android:color/system_surface_container_high_light" /> + <corners android:radius="16dp" /> + <solid android:color="@color/dropdown_container" /> </shape> </item> </ripple>
\ No newline at end of file diff --git a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml deleted file mode 100644 index e4e9f7ac85a9..000000000000 --- a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml +++ /dev/null @@ -1,37 +0,0 @@ -<!-- - ~ Copyright (C) 2023 The Android Open 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. - --> - -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@android:id/content" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/autofill.Dataset"> - <ImageView - android:id="@android:id/icon1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_centerVertical="true" - android:layout_alignParentStart="true" - android:background="@null"/> - <TextView - android:id="@android:id/text1" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentTop="true" - android:layout_toEndOf="@android:id/icon1" - style="@style/autofill.TextAppearance"/> - -</RelativeLayout> diff --git a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml new file mode 100644 index 000000000000..cb6c6b473244 --- /dev/null +++ b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml @@ -0,0 +1,45 @@ +<!-- + ~ Copyright (C) 2023 The Android Open 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. + --> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@android:id/content" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:maxWidth="@dimen/autofill_dropdown_layout_width" + android:elevation="3dp"> + + <ImageView + android:id="@android:id/icon1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:layout_alignParentStart="true" + android:background="@null"/> + <TextView + android:id="@android:id/text1" + android:layout_width="@dimen/autofill_dropdown_text_width" + android:layout_height="wrap_content" + android:layout_alignParentTop="true" + android:layout_toEndOf="@android:id/icon1" + style="@style/autofill.TextTitle"/> + <TextView + android:id="@android:id/text2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/text1" + android:layout_toEndOf="@android:id/icon1" + style="@style/autofill.TextSubtitle"/> + +</RelativeLayout> diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml index 63b9f24d9033..dcb7ef9c3ed8 100644 --- a/packages/CredentialManager/res/values/colors.xml +++ b/packages/CredentialManager/res/values/colors.xml @@ -16,23 +16,8 @@ <!-- Color palette --> <resources> - <color name="autofill_light_colorPrimary">@color/primary_material_light</color> - <color name="autofill_light_colorAccent">@color/accent_material_light</color> - <color name="autofill_light_colorControlHighlight">@color/ripple_material_light</color> - <color name="autofill_light_colorButtonNormal">@color/button_material_light</color> - - <!-- Text colors --> - <color name="autofill_light_textColorPrimary">@color/abc_primary_text_material_light</color> - <color name="autofill_light_textColorSecondary">@color/abc_secondary_text_material_light</color> - <color name="autofill_light_textColorHint">@color/abc_hint_foreground_material_light</color> - <color name="autofill_light_textColorHintInverse">@color/abc_hint_foreground_material_dark - </color> - <color name="autofill_light_textColorHighlight">@color/highlighted_text_material_light</color> - <color name="autofill_light_textColorLink">@color/autofill_light_colorAccent</color> - <!-- These colors are used for Remote Views. --> - <color name="background_dark_mode">#0E0C0B</color> - <color name="background">#F1F3F4</color> - <color name="text_primary_dark_mode">#DFDEDB</color> - <color name="text_primary">#202124</color> + <color name="text_primary">#1A1B20</color> + <color name="text_secondary">#44474F</color> + <color name="dropdown_container">#F3F3FA</color> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml index 67003a330974..2a4719d027e2 100644 --- a/packages/CredentialManager/res/values/dimens.xml +++ b/packages/CredentialManager/res/values/dimens.xml @@ -17,6 +17,12 @@ --> <resources> - <dimen name="autofill_view_padding">16dp</dimen> - <dimen name="autofill_icon_size">16dp</dimen> + <dimen name="autofill_view_top_padding">12dp</dimen> + <dimen name="autofill_view_right_padding">24dp</dimen> + <dimen name="autofill_view_bottom_padding">12dp</dimen> + <dimen name="autofill_view_left_padding">16dp</dimen> + <dimen name="autofill_view_icon_to_text_padding">10dp</dimen> + <dimen name="autofill_icon_size">24dp</dimen> + <dimen name="autofill_dropdown_layout_width">296dp</dimen> + <dimen name="autofill_dropdown_text_width">240dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/res/values/styles.xml b/packages/CredentialManager/res/values/styles.xml index 4a5761acdd83..7de941ebd4a5 100644 --- a/packages/CredentialManager/res/values/styles.xml +++ b/packages/CredentialManager/res/values/styles.xml @@ -15,24 +15,13 @@ --> <resources> - <style name="autofill.TextAppearance.Small" parent="@style/autofill.TextAppearance"> - <item name="android:textSize">12sp</item> - </style> - - - <style name="autofill.Dataset" parent=""> - <item name="android:background">@drawable/autofill_light_selectable_item_background</item> - </style> - - <style name="autofill.TextAppearance" parent=""> - <item name="android:textColor">@color/autofill_light_textColorPrimary</item> - <item name="android:textColorHint">@color/autofill_light_textColorHint</item> - <item name="android:textColorHighlight">@color/autofill_light_textColorHighlight</item> - <item name="android:textColorLink">@color/autofill_light_textColorLink</item> + <style name="autofill.TextTitle" parent=""> + <item name="android:fontFamily">google-sans-medium</item> <item name="android:textSize">14sp</item> </style> - <style name="autofill.TextAppearance.Primary"> - <item name="android:textColor">@color/autofill_light_textColorPrimary</item> + <style name="autofill.TextSubtitle" parent=""> + <item name="android:fontFamily">google-sans-text</item> + <item name="android:textSize">12sp</item> </style> </resources>
\ No newline at end of file diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index b2c23a401117..58467afe43a4 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -57,6 +57,7 @@ import com.android.credentialmanager.common.ui.RemoteViewsFactory import com.android.credentialmanager.getflow.ProviderDisplayInfo import com.android.credentialmanager.getflow.toProviderDisplayInfo import com.android.credentialmanager.ktx.credentialEntry +import com.android.credentialmanager.model.CredentialType import com.android.credentialmanager.model.get.CredentialEntryInfo import com.android.credentialmanager.model.get.ProviderInfo import org.json.JSONException @@ -313,12 +314,14 @@ class CredentialAutofillService : AutofillService() { var i = 0 var datasetAdded = false - val duplicateDisplayNames: MutableMap<String, Boolean> = mutableMapOf() + val duplicateDisplayNamesForPasskeys: MutableMap<String, Boolean> = mutableMapOf() providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach { val credentialEntry = it.sortedCredentialEntryList.first() - credentialEntry.displayName?.let {displayName -> - val duplicateEntry = duplicateDisplayNames.contains(displayName) - duplicateDisplayNames[displayName] = duplicateEntry + if (credentialEntry.credentialType == CredentialType.PASSKEY) { + credentialEntry.displayName?.let { displayName -> + val duplicateEntry = duplicateDisplayNamesForPasskeys.contains(displayName) + duplicateDisplayNamesForPasskeys[displayName] = duplicateEntry + } } } providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{ @@ -355,12 +358,19 @@ class CredentialAutofillService : AutofillService() { } else { spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1] } - val displayName : String = primaryEntry.displayName ?: primaryEntry.userName + val displayName: String = if (primaryEntry.credentialType == CredentialType.PASSKEY + && primaryEntry.displayName != null) { + primaryEntry.displayName!! + } else { + primaryEntry.userName + } val sliceBuilder = InlineSuggestionUi .newContentBuilder(pendingIntent) .setTitle(displayName) sliceBuilder.setStartIcon(icon) - if (duplicateDisplayNames[displayName] == true) { + if (primaryEntry.credentialType == + CredentialType.PASSKEY && duplicateDisplayNamesForPasskeys[displayName] + == true) { sliceBuilder.setSubtitle(primaryEntry.userName) } inlinePresentation = InlinePresentation( diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt index 4dc7f00c1550..e039dead043e 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt @@ -21,6 +21,7 @@ import android.content.res.Configuration import android.widget.RemoteViews import androidx.core.content.ContextCompat import com.android.credentialmanager.model.get.CredentialEntryInfo +import com.android.credentialmanager.model.CredentialType import android.graphics.drawable.Icon class RemoteViewsFactory { @@ -29,48 +30,87 @@ class RemoteViewsFactory { private const val setAdjustViewBoundsMethodName = "setAdjustViewBounds" private const val setMaxHeightMethodName = "setMaxHeight" private const val setBackgroundResourceMethodName = "setBackgroundResource" + private const val bulletPoint = "\u2022" + private const val passwordCharacterLength = 15 fun createDropdownPresentation( context: Context, icon: Icon, credentialEntryInfo: CredentialEntryInfo ): RemoteViews { - val padding = context.resources.getDimensionPixelSize(com.android - .credentialmanager.R.dimen.autofill_view_padding) var layoutId: Int = com.android.credentialmanager.R.layout - .autofill_dataset_left_with_item_tag_hint + .credman_dropdown_presentation_layout val remoteViews = RemoteViews(context.packageName, layoutId) - setRemoteViewsPaddings(remoteViews, padding) - val textColorPrimary = getTextColorPrimary(isDarkMode(context), context); - remoteViews.setTextColor(android.R.id.text1, textColorPrimary); - remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName) - + if (credentialEntryInfo.credentialType == CredentialType.UNKNOWN) { + return remoteViews + } + setRemoteViewsPaddings(remoteViews, context) + if (credentialEntryInfo.credentialType == CredentialType.PASSKEY) { + val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName + remoteViews.setTextViewText(android.R.id.text1, displayName) + val secondaryText = if (credentialEntryInfo.displayName != null) + (credentialEntryInfo.userName + " " + bulletPoint + " " + + credentialEntryInfo.credentialTypeDisplayName + + " " + bulletPoint + " " + credentialEntryInfo.providerDisplayName) + else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " " + + credentialEntryInfo.providerDisplayName) + remoteViews.setTextViewText(android.R.id.text2, secondaryText) + } else { + remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName) + remoteViews.setTextViewText(android.R.id.text2, + bulletPoint.repeat(passwordCharacterLength)) + } + val textColorPrimary = ContextCompat.getColor(context, + com.android.credentialmanager.R.color.text_primary) + remoteViews.setTextColor(android.R.id.text1, textColorPrimary) + val textColorSecondary = ContextCompat.getColor(context, com.android + .credentialmanager.R.color.text_secondary) + remoteViews.setTextColor(android.R.id.text2, textColorSecondary) remoteViews.setImageViewIcon(android.R.id.icon1, icon); remoteViews.setBoolean( android.R.id.icon1, setAdjustViewBoundsMethodName, true); remoteViews.setInt( android.R.id.icon1, - setMaxHeightMethodName, + setMaxHeightMethodName, context.resources.getDimensionPixelSize( com.android.credentialmanager.R.dimen.autofill_icon_size)); - val drawableId = if (isDarkMode(context)) - com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one_dark - else com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one + val drawableId = + com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one remoteViews.setInt( android.R.id.content, setBackgroundResourceMethodName, drawableId); return remoteViews } private fun setRemoteViewsPaddings( - remoteViews: RemoteViews, - padding: Int) { - val halfPadding = padding / 2 + remoteViews: RemoteViews, context: Context) { + val leftPadding = context.resources.getDimensionPixelSize( + com.android.credentialmanager.R.dimen.autofill_view_left_padding) + val iconToTextPadding = context.resources.getDimensionPixelSize( + com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding) + val rightPadding = context.resources.getDimensionPixelSize( + com.android.credentialmanager.R.dimen.autofill_view_right_padding) + val topPadding = context.resources.getDimensionPixelSize( + com.android.credentialmanager.R.dimen.autofill_view_top_padding) + val bottomPadding = context.resources.getDimensionPixelSize( + com.android.credentialmanager.R.dimen.autofill_view_bottom_padding) + remoteViews.setViewPadding( + android.R.id.icon1, + leftPadding, + /* top=*/0, + /* right=*/0, + /* bottom=*/0) remoteViews.setViewPadding( android.R.id.text1, - halfPadding, - halfPadding, - halfPadding, - halfPadding) + iconToTextPadding, + /* top=*/topPadding, + /* right=*/rightPadding, + /* bottom=*/0) + remoteViews.setViewPadding( + android.R.id.text2, + iconToTextPadding, + /* top=*/0, + /* right=*/rightPadding, + /* bottom=*/bottomPadding) } private fun isDarkMode(context: Context): Boolean { @@ -78,11 +118,5 @@ class RemoteViewsFactory { Configuration.UI_MODE_NIGHT_MASK return currentNightMode == Configuration.UI_MODE_NIGHT_YES } - - private fun getTextColorPrimary(darkMode: Boolean, context: Context): Int { - return if (darkMode) ContextCompat.getColor( - context, com.android.credentialmanager.R.color.text_primary_dark_mode) - else ContextCompat.getColor(context, com.android.credentialmanager.R.color.text_primary) - } } } diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml index 3d0b945b7f79..b1e5d755b788 100644 --- a/packages/InputDevices/res/values-sv/strings.xml +++ b/packages/InputDevices/res/values-sv/strings.xml @@ -3,50 +3,50 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="8016145283189546017">"Indataenheter"</string> <string name="keyboard_layouts_label" msgid="6688773268302087545">"Androids tangentbord"</string> - <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Engelskt (Storbritannien)"</string> - <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Engelskt (USA)"</string> - <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelskt (USA), internationellt"</string> - <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelskt (USA), colemak"</string> - <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelskt (USA), dvorak"</string> - <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelskt (USA), workman"</string> - <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tyskt"</string> - <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string> - <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string> + <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"engelska (Storbritannien)"</string> + <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"engelska (USA)"</string> + <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"engelska (USA), internationell"</string> + <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"engelska (USA), colemak"</string> + <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"engelska (USA), dvorak"</string> + <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"engelska (USA), workman"</string> + <string name="keyboard_layout_german_label" msgid="8451565865467909999">"tyska"</string> + <string name="keyboard_layout_french_label" msgid="813450119589383723">"franska"</string> + <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"franska (Kanada)"</string> <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"ryska"</string> - <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"Ryskt, Mac"</string> - <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"Spanskt"</string> - <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"Franskt (Schweiz)"</string> - <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tyskt (Schweiz)"</string> - <string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiskt"</string> + <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"ryska, Mac"</string> + <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"spanska"</string> + <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"franska (Schweiz)"</string> + <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"tyska (Schweiz)"</string> + <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgiska"</string> <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulgariska"</string> - <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariska (fonetiskt)"</string> - <string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienskt"</string> - <string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string> - <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norskt"</string> - <string name="keyboard_layout_swedish" msgid="732959109088479351">"Svenskt"</string> - <string name="keyboard_layout_finnish" msgid="5585659438924315466">"Finskt"</string> - <string name="keyboard_layout_croatian" msgid="4172229471079281138">"Kroatiskt"</string> - <string name="keyboard_layout_czech" msgid="1349256901452975343">"Tjeckiskt"</string> - <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"Tjeckiskt QWERTY"</string> - <string name="keyboard_layout_estonian" msgid="8775830985185665274">"Estniskt"</string> - <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"Ungerskt"</string> - <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"Isländskt"</string> - <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"Portugisiskt (Brasilien)"</string> - <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"Portugisiskt"</string> - <string name="keyboard_layout_slovak" msgid="2469379934672837296">"Slovakiskt"</string> - <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"Slovenskt"</string> - <string name="keyboard_layout_turkish" msgid="7736163250907964898">"Turkiskt"</string> + <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bulgariska (fonetiskt)"</string> + <string name="keyboard_layout_italian" msgid="6497079660449781213">"italienska"</string> + <string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string> + <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norska"</string> + <string name="keyboard_layout_swedish" msgid="732959109088479351">"svenska"</string> + <string name="keyboard_layout_finnish" msgid="5585659438924315466">"finska"</string> + <string name="keyboard_layout_croatian" msgid="4172229471079281138">"kroatiska"</string> + <string name="keyboard_layout_czech" msgid="1349256901452975343">"tjeckiska"</string> + <string name="keyboard_layout_czech_qwerty" msgid="3331402534128515501">"tjeckiska QWERTY"</string> + <string name="keyboard_layout_estonian" msgid="8775830985185665274">"estniska"</string> + <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"ungerska"</string> + <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"isländska"</string> + <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"portugisiska (Brasilien)"</string> + <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugisiska"</string> + <string name="keyboard_layout_slovak" msgid="2469379934672837296">"slovakiska"</string> + <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenska"</string> + <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turkiska"</string> <string name="keyboard_layout_turkish_f" msgid="9130320856010776018">"turkiska, F"</string> - <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"Ukrainskt"</string> + <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrainska"</string> <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arabiska"</string> <string name="keyboard_layout_greek" msgid="7289253560162386040">"grekiska"</string> <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebreiska"</string> - <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"Litauiska"</string> - <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"Spanska (latinamerikansk)"</string> + <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litauiska"</string> + <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"spanska (latinamerikansk)"</string> <string name="keyboard_layout_latvian" msgid="4405417142306250595">"lettiska"</string> <string name="keyboard_layout_persian" msgid="3920643161015888527">"persiska"</string> <string name="keyboard_layout_azerbaijani" msgid="7315895417176467567">"azerbajdzjanska"</string> - <string name="keyboard_layout_polish" msgid="1121588624094925325">"Polska"</string> + <string name="keyboard_layout_polish" msgid="1121588624094925325">"polska"</string> <string name="keyboard_layout_belarusian" msgid="7619281752698687588">"vitryska"</string> <string name="keyboard_layout_mongolian" msgid="7678483495823936626">"mongoliska"</string> <string name="keyboard_layout_georgian" msgid="4596185456863747454">"georgiska"</string> diff --git a/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml b/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml index 7f1651721d84..8127e1a6d5a2 100644 --- a/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml +++ b/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" @@ -8,7 +8,7 @@ errorLine2=" ~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveIcon.java" - line="78" + line="79" column="34"/> </issue> @@ -19,7 +19,7 @@ errorLine2=" ~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveIcon.java" - line="90" + line="91" column="36"/> </issue> @@ -30,7 +30,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java" - line="43" + line="45" column="46"/> </issue> @@ -41,7 +41,7 @@ errorLine2=" ~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java" - line="65" + line="67" column="9"/> </issue> @@ -52,7 +52,7 @@ errorLine2=" ~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java" - line="72" + line="74" column="9"/> </issue> @@ -63,7 +63,7 @@ errorLine2=" ~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java" - line="80" + line="82" column="9"/> </issue> @@ -74,8 +74,8 @@ errorLine2=" ~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java" - line="105" + line="107" column="26"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index ffe3d1d633d7..5da4b9518a31 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -61,7 +61,7 @@ android_library { "src/**/*.kt", ], lint: { - baseline_filename: "lint-baseline.xml", + extra_check_modules: ["SettingsLibLintChecker"], }, } diff --git a/packages/SettingsLib/EmergencyNumber/lint-baseline.xml b/packages/SettingsLib/EmergencyNumber/lint-baseline.xml index e9c687fd3227..13bf5f54ead3 100644 --- a/packages/SettingsLib/EmergencyNumber/lint-baseline.xml +++ b/packages/SettingsLib/EmergencyNumber/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" @@ -8,7 +8,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="77" + line="81" column="41"/> </issue> @@ -19,7 +19,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="78" + line="82" column="45"/> </issue> @@ -30,18 +30,18 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="78" + line="82" column="62"/> </issue> <issue id="NewApi" message="Call requires API level 29 (current min is 21): `android.telephony.TelephonyManager#getEmergencyNumberList`" - errorLine1=" Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(" + errorLine1=" Map<Integer, List<EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList(" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="173" + line="177" column="74"/> </issue> @@ -52,7 +52,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="196" + line="200" column="41"/> </issue> @@ -63,7 +63,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="219" + line="223" column="69"/> </issue> @@ -74,7 +74,7 @@ errorLine2=" ~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="234" + line="238" column="41"/> </issue> @@ -85,8 +85,8 @@ errorLine2=" ~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java" - line="251" + line="255" column="52"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp index d9f74dadf281..010a6ce9d4d9 100644 --- a/packages/SettingsLib/MainSwitchPreference/Android.bp +++ b/packages/SettingsLib/MainSwitchPreference/Android.bp @@ -28,7 +28,4 @@ android_library { "com.android.extservices", "com.android.healthfitness", ], - lint: { - baseline_filename: "lint-baseline.xml", - }, } diff --git a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml b/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml deleted file mode 100644 index cfa64a487407..000000000000 --- a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> - - <issue - id="NewApi" - message="`@android:dimen/config_restrictedIconSize` requires API level 29 (current min is 28)" - errorLine1=' <dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>' - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml" - line="21" - column="52"/> - </issue> - -</issues>
\ No newline at end of file diff --git a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml index 26d05a621c22..45a07fe9eee3 100644 --- a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml +++ b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" - message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`" - errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));" - errorLine2=" ~~"> + message="Call requires API level 28 (current min is 23): `android.content.Context#createPackageContextAsUser`" + errorLine1=" userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java" - line="97" - column="56"/> + line="64" + column="35"/> </issue> <issue id="NewApi" - message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`" - errorLine1=" return um.getUserProfiles().contains(UserHandle.of(userId));" - errorLine2=" ~~"> + message="Call requires API level 29 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerUser`" + errorLine1=" if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java" - line="140" - column="57"/> + line="74" + column="32"/> </issue> <issue @@ -36,35 +36,35 @@ <issue id="NewApi" - message="Call requires API level 28 (current min is 23): `android.content.Context#createPackageContextAsUser`" - errorLine1=" userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`" + errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));" + errorLine2=" ~~"> <location file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java" - line="64" - column="35"/> + line="97" + column="56"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerUser`" - errorLine1=" if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 29 (current min is 23): `android.content.Context#startActivityAsUser`" + errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));" + errorLine2=" ~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java" - line="74" - column="32"/> + line="97" + column="17"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 23): `android.content.Context#startActivityAsUser`" - errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`" + errorLine1=" return um.getUserProfiles().contains(UserHandle.of(userId));" + errorLine2=" ~~"> <location file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java" - line="97" - column="17"/> + line="120" + column="57"/> </issue> </issues>
\ No newline at end of file diff --git a/packages/SettingsLib/SchedulesProvider/lint-baseline.xml b/packages/SettingsLib/SchedulesProvider/lint-baseline.xml index 0744710e5224..db6a88210cd4 100644 --- a/packages/SettingsLib/SchedulesProvider/lint-baseline.xml +++ b/packages/SettingsLib/SchedulesProvider/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" diff --git a/packages/SettingsLib/SearchProvider/lint-baseline.xml b/packages/SettingsLib/SearchProvider/lint-baseline.xml index 53346e030be2..3cfca1d2cdcb 100644 --- a/packages/SettingsLib/SearchProvider/lint-baseline.xml +++ b/packages/SettingsLib/SearchProvider/lint-baseline.xml @@ -1,36 +1,47 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" - message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableResource`" - errorLine1=" super(" - errorLine2=" ~~~~~"> + message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexablesProvider`" + errorLine1="public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="107" - column="13"/> + line="34" + column="56"/> </issue> <issue id="NewApi" - message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableResource`" - errorLine1=" public static final class SearchIndexableIntentResource extends SearchIndexableResource {" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexablesContract#INDEXABLES_XML_RES_COLUMNS`" + errorLine1=" final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="97" - column="69"/> + line="45" + column="54"/> </issue> <issue id="NewApi" - message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexablesProvider`" - errorLine1="public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#rank`" + errorLine1=" .add(XmlResource.COLUMN_RANK, indexableResource.rank)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="34" + line="50" + column="51"/> + </issue> + + <issue + id="NewApi" + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableResource#xmlResId`" + errorLine1=" .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" + line="51" column="56"/> </issue> @@ -58,79 +69,68 @@ <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`" - errorLine1=' this.intentAction = "android.intent.action.MAIN";' - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="113" - column="17"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`" - errorLine1=" this.intentAction = intentAction;" - errorLine2=" ~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`" + errorLine1=" indexableResource.intentTargetClass);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="115" - column="17"/> + line="56" + column="29"/> </issue> <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`" - errorLine1=" indexableResource.intentTargetClass);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableResource`" + errorLine1=" public static final class SearchIndexableIntentResource extends SearchIndexableResource {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="56" - column="29"/> + line="97" + column="69"/> </issue> <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`" - errorLine1=" this.intentTargetClass = className;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableResource`" + errorLine1=" super(" + errorLine2=" ~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="117" + line="107" column="13"/> </issue> <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#rank`" - errorLine1=" .add(XmlResource.COLUMN_RANK, indexableResource.rank)" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`" + errorLine1=' this.intentAction = "android.intent.action.MAIN";' + errorLine2=" ~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="50" - column="51"/> + line="113" + column="17"/> </issue> <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableResource#xmlResId`" - errorLine1=" .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`" + errorLine1=" this.intentAction = intentAction;" + errorLine2=" ~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="51" - column="56"/> + line="115" + column="17"/> </issue> <issue id="NewApi" - message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexablesContract#INDEXABLES_XML_RES_COLUMNS`" - errorLine1=" final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`" + errorLine1=" this.intentTargetClass = className;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java" - line="45" - column="54"/> + line="117" + column="13"/> </issue> </issues>
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt index a9974dc7d389..514ad66919ee 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt @@ -39,6 +39,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsTheme @@ -68,6 +71,7 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) -> ) { val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) Button( + modifier = Modifier.semantics { role = Role.DropdownList }, onClick = { expanded = true }, colors = ButtonDefaults.buttonColors( containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer, diff --git a/packages/SettingsLib/Tile/lint-baseline.xml b/packages/SettingsLib/Tile/lint-baseline.xml index 326ec0dbaa72..56b1bcafbae2 100644 --- a/packages/SettingsLib/Tile/lint-baseline.xml +++ b/packages/SettingsLib/Tile/lint-baseline.xml @@ -1,55 +1,59 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" - message="Call requires API level 24 (current min is 21): `java.lang.Iterable#forEach`" - errorLine1=" controllers.forEach(controller -> {" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java" - line="79" - column="21"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#createWithResource`"> + message="Call requires API level 29 (current min is 21): `android.os.Parcel#writeBoolean`" + errorLine1=" dest.writeBoolean(this instanceof ProviderTile);" + errorLine2=" ~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java" - line="312"/> + line="114" + column="14"/> </issue> <issue id="NewApi" - message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#setTint`"> + message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#createWithResource`" + errorLine1=" final Icon icon = Icon.createWithResource(componentInfo.packageName, iconResId);" + errorLine2=" ~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java" - line="318"/> + line="326" + column="36"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 21): `android.os.Parcel#readBoolean`"> + message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#setTint`" + errorLine1=" icon.setTint(tintColor);" + errorLine2=" ~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java" - line="373"/> + line="332" + column="22"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 21): `android.os.Parcel#writeBoolean`"> + message="Call requires API level 29 (current min is 21): `android.os.Parcel#readBoolean`" + errorLine1=" final boolean isProviderTile = source.readBoolean();" + errorLine2=" ~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java" - line="108"/> + line="387" + column="51"/> </issue> <issue id="NewApi" - message="Call requires API level 31 (current min is 21): `android.content.Context#getAttributionSource`"> + message="Call requires API level 31 (current min is 21): `android.content.Context#getAttributionSource`" + errorLine1=" return provider.call(context.getAttributionSource()," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java" - line="565"/> + line="601" + column="42"/> </issue> </issues>
\ No newline at end of file diff --git a/packages/SettingsLib/Utils/lint-baseline.xml b/packages/SettingsLib/Utils/lint-baseline.xml index 3fcd56c557e8..2f6cc3ae8719 100644 --- a/packages/SettingsLib/Utils/lint-baseline.xml +++ b/packages/SettingsLib/Utils/lint-baseline.xml @@ -1,26 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" - message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`" - errorLine1=" mContext.getPackageName(), 0, UserHandle.of(managedUserId)" - errorLine2=" ~~"> - <location - file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="119" - column="70"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`" - errorLine1=" intent, 0, UserHandle.of(managedUserId));" - errorLine2=" ~~"> + message="Call requires API level 24 (current min is 23): `android.os.UserManager#isManagedProfile`" + errorLine1=" return context.getSystemService(UserManager.class).isManagedProfile(userId)" + errorLine2=" ~~~~~~~~~~~~~~~~"> <location - file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="150" - column="47"/> + file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java" + line="62" + column="60"/> </issue> <issue @@ -36,68 +25,68 @@ <issue id="NewApi" - message="Call requires API level 24 (current min is 21): `android.os.UserManager#isManagedProfile`" - errorLine1=" if (mUserManager.isManagedProfile(id)) {" - errorLine2=" ~~~~~~~~~~~~~~~~"> + message="Call requires API level 29 (current min is 21): `android.content.Context#startActivityAsUser`" + errorLine1=" activityContext.startActivityAsUser(intent, UserHandle.of(userId));" + errorLine2=" ~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="173" - column="30"/> + line="80" + column="29"/> </issue> <issue id="NewApi" - message="Call requires API level 24 (current min is 23): `android.os.UserManager#isManagedProfile`" - errorLine1=" return context.getSystemService(UserManager.class).isManagedProfile(userId)" - errorLine2=" ~~~~~~~~~~~~~~~~"> + message="Call requires API level 28 (current min is 21): `android.content.Context#createPackageContextAsUser`" + errorLine1=" mContext.createPackageContextAsUser(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location - file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java" - line="62" - column="60"/> + file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" + line="118" + column="30"/> </issue> <issue id="NewApi" - message="Call requires API level 26 (current min is 21): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`" - errorLine1=" return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`" + errorLine1=" mContext.getPackageName(), 0, UserHandle.of(managedUserId)" + errorLine2=" ~~"> <location file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="163" - column="37"/> + line="119" + column="70"/> </issue> <issue id="NewApi" - message="Call requires API level 28 (current min is 21): `android.content.Context#createPackageContextAsUser`" - errorLine1=" mContext.createPackageContextAsUser(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 29 (current min is 21): `android.content.pm.PackageManager#queryIntentActivitiesAsUser`" + errorLine1=" mPackageManager.queryIntentActivitiesAsUser(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="118" - column="30"/> + line="149" + column="33"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 21): `android.content.Context#startActivityAsUser`" - errorLine1=" activityContext.startActivityAsUser(intent, UserHandle.of(userId));" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`" + errorLine1=" intent, 0, UserHandle.of(managedUserId));" + errorLine2=" ~~"> <location file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="80" - column="29"/> + line="150" + column="47"/> </issue> <issue id="NewApi" - message="Call requires API level 29 (current min is 21): `android.content.pm.PackageManager#queryIntentActivitiesAsUser`" - errorLine1=" mPackageManager.queryIntentActivitiesAsUser(" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 26 (current min is 21): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`" + errorLine1=" return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" - line="149" - column="33"/> + line="163" + column="37"/> </issue> <issue @@ -111,4 +100,15 @@ column="53"/> </issue> + <issue + id="NewApi" + message="Call requires API level 24 (current min is 21): `android.os.UserManager#isManagedProfile`" + errorLine1=" if (mUserManager.isManagedProfile(id)) {" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java" + line="173" + column="30"/> + </issue> + </issues>
\ No newline at end of file diff --git a/packages/SettingsLib/lint-baseline.xml b/packages/SettingsLib/lint-baseline.xml deleted file mode 100644 index d6a23fd827d9..000000000000 --- a/packages/SettingsLib/lint-baseline.xml +++ /dev/null @@ -1,204 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0"> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.bluetooth.BluetoothDevice#setAlias`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java" - line="584"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiInfo#getSubscriptionId`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java" - line="248"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiInfo#getSubscriptionId`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java" - line="278"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiManager#registerSubsystemRestartTrackingCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="201"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiManager#unregisterSubsystemRestartTrackingCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="208"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.os.UserManager#isUserForeground`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java" - line="78"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#isDataCapable`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/Utils.java" - line="498"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#isDataCapable`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java" - line="225"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#registerTelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="215"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#registerTelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="86"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#unregisterTelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="222"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#unregisterTelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="88"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java" - line="66"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java" - line="49"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSimStatusImeiInfoPreferenceController.java" - line="33"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.net.wifi.WifiManager.SubsystemRestartTrackingCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="64"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="125"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.CarrierNetworkListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="124"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DataActivityListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="123"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DataConnectionStateListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="122"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DisplayInfoListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="126"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.ServiceStateListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="120"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.SignalStrengthsListener`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="121"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java" - line="79"/> - </issue> - - <issue - id="NewApi" - message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback`"> - <location - file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java" - line="119"/> - </issue> - -</issues>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 640d4e949a94..071258d593e4 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -60,7 +60,7 @@ <string name="wifi_not_in_range" msgid="1541760821805777772">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string> <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="wifi_no_internet" msgid="1774198889176926299">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string> - <string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ನಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string> + <string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ನಿಂದ ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ನೆಟ್ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> <string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಮೂಲಕ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string> diff --git a/packages/SettingsLib/search/Android.bp b/packages/SettingsLib/search/Android.bp index 3b14712cc87e..390c9d2e98de 100644 --- a/packages/SettingsLib/search/Android.bp +++ b/packages/SettingsLib/search/Android.bp @@ -12,9 +12,6 @@ java_library { visibility: ["//visibility:private"], srcs: ["interface-src/**/*.java"], host_supported: true, - lint: { - baseline_filename: "lint-baseline.xml", - }, } android_library { diff --git a/packages/SettingsLib/search/lint-baseline.xml b/packages/SettingsLib/search/lint-baseline.xml index 7ec512b617d7..61cdb051feeb 100644 --- a/packages/SettingsLib/search/lint-baseline.xml +++ b/packages/SettingsLib/search/lint-baseline.xml @@ -1,26 +1,26 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NewApi" - message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableData`" - errorLine1=" super(context);" - errorLine2=" ~~~~~"> + message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableData`" + errorLine1="public class SearchIndexableRaw extends SearchIndexableData {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~"> <location file="frameworks/base/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableRaw.java" - line="62" - column="9"/> + line="29" + column="41"/> </issue> <issue id="NewApi" - message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableData`" - errorLine1="public class SearchIndexableRaw extends SearchIndexableData {" - errorLine2=" ~~~~~~~~~~~~~~~~~~~"> + message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableData`" + errorLine1=" super(context);" + errorLine2=" ~~~~~"> <location file="frameworks/base/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableRaw.java" - line="29" - column="41"/> + line="62" + column="9"/> </issue> </issues>
\ No newline at end of file diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java index 8e5396fef744..d9024575f247 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java @@ -19,6 +19,7 @@ package com.android.settingslib; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE; import static android.app.admin.DevicePolicyManager.MTE_NOT_CONTROLLED_BY_POLICY; import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER; +import static android.app.role.RoleManager.ROLE_FINANCED_DEVICE_KIOSK; import static com.android.settingslib.Utils.getColorAttrDefaultColor; @@ -27,6 +28,7 @@ import android.annotation.UserIdInt; import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.admin.DevicePolicyManager; +import android.app.role.RoleManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -70,6 +72,10 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils { private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG); private static final Set<String> ECM_KEYS = new ArraySet<>(); + // TODO(b/281701062): reference role name from role manager once its exposed. + private static final String ROLE_DEVICE_LOCK_CONTROLLER = + "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER"; + static { if (android.security.Flags.extendEcmToAllSettings()) { ECM_KEYS.add(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW); @@ -476,16 +482,27 @@ public class RestrictedLockUtilsInternal extends RestrictedLockUtils { } /** - * Check if {@param packageName} is restricted by the profile or device owner from using - * metered data. + * Check if user control over metered data usage of {@code packageName} is disabled by the + * profile or device owner. * * @return EnforcedAdmin object containing the enforced admin component and admin user details, - * or {@code null} if the {@param packageName} is not restricted. + * or {@code null} if the user control is not disabled. */ - public static EnforcedAdmin checkIfMeteredDataRestricted(Context context, + public static EnforcedAdmin checkIfMeteredDataUsageUserControlDisabled(Context context, String packageName, int userId) { + RoleManager roleManager = context.getSystemService(RoleManager.class); + UserHandle userHandle = getUserHandleOf(userId); + if (roleManager.getRoleHoldersAsUser(ROLE_FINANCED_DEVICE_KIOSK, userHandle) + .contains(packageName) + || roleManager.getRoleHoldersAsUser(ROLE_DEVICE_LOCK_CONTROLLER, userHandle) + .contains(packageName)) { + // There is no actual device admin for a financed device, but metered data usage + // control should still be disabled for both controller and kiosk apps. + return new EnforcedAdmin(); + } + final EnforcedAdmin enforcedAdmin = getProfileOrDeviceOwner(context, - getUserHandleOf(userId)); + userHandle); if (enforcedAdmin == null) { return null; } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java index 5bc271954b25..943e3fc27ebb 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java @@ -70,10 +70,8 @@ public abstract class AbstractWifiMacAddressPreferenceController @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); - if (isAvailable()) { - mWifiMacAddress = screen.findPreference(KEY_WIFI_MAC_ADDRESS); - updateConnectivity(); - } + mWifiMacAddress = screen.findPreference(KEY_WIFI_MAC_ADDRESS); + updateConnectivity(); } @Override @@ -84,16 +82,16 @@ public abstract class AbstractWifiMacAddressPreferenceController @SuppressLint("HardwareIds") @Override protected void updateConnectivity() { + if (mWifiManager == null || mWifiMacAddress == null) { + return; + } + final String[] macAddresses = mWifiManager.getFactoryMacAddresses(); String macAddress = null; if (macAddresses != null && macAddresses.length > 0) { macAddress = macAddresses[0]; } - if (mWifiMacAddress == null) { - return; - } - if (TextUtils.isEmpty(macAddress) || macAddress.equals(WifiInfo.DEFAULT_MAC_ADDRESS)) { mWifiMacAddress.setSummary(R.string.status_unavailable); } else { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java index 24fd06e51418..e7487e857464 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -73,13 +74,13 @@ public class HearingAidDeviceManagerTest { private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22"; private final BluetoothClass DEVICE_CLASS = createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE); + private final Context mContext = ApplicationProvider.getApplicationContext(); private CachedBluetoothDevice mCachedDevice1; private CachedBluetoothDevice mCachedDevice2; private CachedBluetoothDeviceManager mCachedDeviceManager; private HearingAidDeviceManager mHearingAidDeviceManager; private AudioDeviceAttributes mHearingDeviceAttribute; - private final Context mContext = ApplicationProvider.getApplicationContext(); @Spy private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext); @Mock @@ -517,6 +518,8 @@ public class HearingAidDeviceManagerTest { when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn( mHearingDeviceAttribute); when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true); + doReturn(true).when(mHelper).setPreferredDeviceRoutingStrategies(anyList(), + eq(mHearingDeviceAttribute), anyInt()); mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1); @@ -529,6 +532,8 @@ public class HearingAidDeviceManagerTest { when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn( mHearingDeviceAttribute); when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(false); + doReturn(true).when(mHelper).setPreferredDeviceRoutingStrategies(anyList(), any(), + anyInt()); mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1); diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 1481d97a04fa..16de478d99c1 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -231,6 +231,7 @@ public class SettingsBackupTest { Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT, Settings.Global.ENABLE_MULTI_SLOT_TIMEOUT_MILLIS, Settings.Global.ENHANCED_4G_MODE_ENABLED, + Settings.Global.ENABLE_16K_PAGES, // Added for 16K developer option Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES, Settings.Global.ERROR_LOGCAT_PREFIX, Settings.Global.EUICC_PROVISIONED, @@ -867,6 +868,7 @@ public class SettingsBackupTest { Settings.Secure.NEARBY_SHARING_SLICE_URI, Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES, Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, + Settings.Secure.PRIVATE_SPACE_AUTO_LOCK, Settings.Secure.RELEASE_COMPRESS_BLOCKS_ON_INSTALL, Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED, Settings.Secure.SHOW_QR_CODE_SCANNER_SETTING, diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d3a89f447d1f..d61ae7eccc42 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -438,6 +438,7 @@ android_robolectric_test { "androidx.core_core-animation-testing", "androidx.test.ext.junit", "inline-mockito-robolectric-prebuilt", + "platform-parametric-runner-lib", ], libs: [ "android.test.runner", diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 21263a92ae26..f7b1a26c9df9 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -10,6 +10,13 @@ flag { } flag { + name: "floating_menu_drag_to_hide" + namespace: "accessibility" + description: "Allows users to hide the FAB then use notification to dismiss or bring it back." + bug: "298718415" +} + +flag { name: "floating_menu_ime_displacement_animation" namespace: "accessibility" description: "Adds an animation for when the FAB is displaced by an IME becoming visible." @@ -28,4 +35,4 @@ flag { namespace: "accessibility" description: "Animates the floating menu's transition between curved and jagged edges." bug: "281140482" -}
\ No newline at end of file +} diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 5b218549de43..c23a49c68363 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -208,6 +208,13 @@ flag { } flag { + name: "compose_bouncer" + namespace: "systemui" + description: "Use the new compose bouncer in SystemUI" + bug: "310005730" +} + +flag { name: "media_in_scene_container" namespace: "systemui" description: "Enable media in the scene container framework" @@ -258,6 +265,15 @@ flag { } flag { + name: "centralized_status_bar_dimens_refactor" + namespace: "systemui" + description: "Refactors shade header and keyguard status bar to read status bar dimens from a" + " central place, instead of reading resources directly. This is to take into account display" + " cutouts and other special cases. " + bug: "317199366" +} + +flag { name: "enable_layout_tracing" namespace: "systemui" description: "Enables detailed traversal slices during measure and layout in perfetto traces" diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt index fd04b5ee0d9c..f4ffb3c66219 100644 --- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -22,6 +22,8 @@ import android.view.View import android.view.WindowInsets import androidx.activity.ComponentActivity import androidx.lifecycle.LifecycleOwner +import com.android.systemui.bouncer.ui.BouncerDialogFactory +import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel import com.android.systemui.people.ui.viewmodel.PeopleViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel @@ -85,6 +87,12 @@ object ComposeFacade : BaseComposeFacade { throwComposeUnavailableError() } + override fun createBouncer( + context: Context, + viewModel: BouncerViewModel, + dialogFactory: BouncerDialogFactory, + ): View = throwComposeUnavailableError() + private fun throwComposeUnavailableError(): Nothing { error( "Compose is not available. Make sure to check isComposeAvailable() before calling any" + diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt index d31547bd0d64..43745f9bf027 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt @@ -28,6 +28,9 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.LifecycleOwner import com.android.compose.theme.PlatformTheme import com.android.compose.ui.platform.DensityAwareComposeView +import com.android.systemui.bouncer.ui.BouncerDialogFactory +import com.android.systemui.bouncer.ui.composable.BouncerContent +import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation import com.android.systemui.common.ui.compose.windowinsets.DisplayCutout import com.android.systemui.common.ui.compose.windowinsets.DisplayCutoutProvider @@ -171,4 +174,14 @@ object ComposeFacade : BaseComposeFacade { private fun Int.toDp(context: Context): Dp { return (this.toFloat() / context.resources.displayMetrics.density).dp } + + override fun createBouncer( + context: Context, + viewModel: BouncerViewModel, + dialogFactory: BouncerDialogFactory, + ): View { + return ComposeView(context).apply { + setContent { PlatformTheme { BouncerContent(viewModel, dialogFactory) } } + } + } } diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt index 1860c9f1656e..2b1268e40f00 100644 --- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt +++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/BouncerSceneModule.kt @@ -16,34 +16,14 @@ package com.android.systemui.scene -import android.app.AlertDialog -import android.content.Context -import com.android.systemui.bouncer.ui.composable.BouncerDialogFactory import com.android.systemui.bouncer.ui.composable.BouncerScene -import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.scene.shared.model.Scene -import com.android.systemui.statusbar.phone.SystemUIDialog import dagger.Binds import dagger.Module -import dagger.Provides import dagger.multibindings.IntoSet @Module interface BouncerSceneModule { @Binds @IntoSet fun bouncerScene(scene: BouncerScene): Scene - - companion object { - - @Provides - @SysUISingleton - fun bouncerSceneDialogFactory(@Application context: Context): BouncerDialogFactory { - return object : BouncerDialogFactory { - override fun invoke(): AlertDialog { - return SystemUIDialog(context) - } - } - } - } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index 6591543f44fe..d9493961e3ed 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -81,6 +81,7 @@ import com.android.compose.animation.scene.transitions import com.android.compose.modifiers.thenIf import com.android.compose.windowsizeclass.LocalWindowSizeClass import com.android.systemui.bouncer.shared.model.BouncerActionButtonModel +import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel @@ -824,10 +825,6 @@ private fun UserSwitcherDropdownMenu( } } -interface BouncerDialogFactory { - operator fun invoke(): AlertDialog -} - /** * Calculates an alpha for the user switcher and bouncer such that it's at `1` when the offset of * the two reaches a stopping point but `0` in the middle of the transition. diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index d638ffe11abe..428bc39c7632 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope +import com.android.systemui.bouncer.ui.BouncerDialogFactory import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.Direction diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 249b3e14ec72..b70486473672 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -1,30 +1,13 @@ package com.android.systemui.communal.ui.compose import androidx.compose.animation.core.tween -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.width -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInteropFilter import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.ElementKey @@ -33,15 +16,14 @@ import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.SceneTransitionLayout -import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.observableTransitionState import com.android.compose.animation.scene.transitions +import com.android.compose.animation.scene.updateSceneTransitionLayoutState import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.transform @@ -66,7 +48,6 @@ val sceneTransitions = transitions { * This is a temporary container to allow the communal UI to use [SceneTransitionLayout] for gesture * handling and transitions before the full Flexiglass layout is ready. */ -@OptIn(ExperimentalComposeUiApi::class, ExperimentalCoroutinesApi::class) @Composable fun CommunalContainer( modifier: Modifier = Modifier, @@ -76,14 +57,18 @@ fun CommunalContainer( viewModel.currentScene .transform { value -> emit(value.toTransitionSceneKey()) } .collectAsState(TransitionSceneKey.Blank) - val sceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) } - // Don't show hub mode UI if keyguard is present. This is important since we're in the shade, - // which can be opened from many locations. + val sceneTransitionLayoutState = + updateSceneTransitionLayoutState( + currentScene, + onChangeScene = { viewModel.onSceneChanged(it.toCommunalSceneKey()) }, + transitions = sceneTransitions, + ) + + // Don't show hub mode UI if keyguard is not present. This is important since we're in the + // shade, which can be opened from many locations. val isKeyguardShowing by viewModel.isKeyguardVisible.collectAsState(initial = false) - // Failsafe to hide the whole SceneTransitionLayout in case of bugginess. - var showSceneTransitionLayout by remember { mutableStateOf(true) } - if (!showSceneTransitionLayout || !isKeyguardShowing) { + if (!isKeyguardShowing) { return } @@ -96,83 +81,30 @@ fun CommunalContainer( onDispose { viewModel.setTransitionState(null) } } - Box(modifier = modifier.fillMaxSize()) { - SceneTransitionLayout( - modifier = Modifier.fillMaxSize(), - currentScene = currentScene, - onChangeScene = { sceneKey -> viewModel.onSceneChanged(sceneKey.toCommunalSceneKey()) }, - transitions = sceneTransitions, - state = sceneTransitionLayoutState, - edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize) + SceneTransitionLayout( + state = sceneTransitionLayoutState, + modifier = modifier.fillMaxSize(), + edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize), + ) { + scene( + TransitionSceneKey.Blank, + userActions = + mapOf( + Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal + ) ) { - scene( - TransitionSceneKey.Blank, - userActions = - mapOf( - Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to - TransitionSceneKey.Communal - ) - ) { - BlankScene { showSceneTransitionLayout = false } - } - - scene( - TransitionSceneKey.Communal, - userActions = - mapOf( - Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to - TransitionSceneKey.Blank - ), - ) { - CommunalScene(viewModel, modifier = modifier) - } + // This scene shows nothing only allowing for transitions to the communal scene. + Box(modifier = Modifier.fillMaxSize()) } - // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't - // block touches anymore. - Box( - modifier = - Modifier.fillMaxSize() - // Offsetting to the left so that edge swipe to open the hub still works. This - // does mean that the very right edge of the hub won't refresh the screen - // timeout, but should be good enough for a temporary solution. - .offset(x = -ContainerDimensions.EdgeSwipeSize) - .pointerInteropFilter { - viewModel.onUserActivity() - if ( - sceneTransitionLayoutState.transitionState.currentScene == - TransitionSceneKey.Blank - ) { - viewModel.onOuterTouch(it) - return@pointerInteropFilter true - } - false - } - ) - } -} - -/** - * Blank scene that shows over keyguard/dream. This scene will eventually show nothing at all and is - * only used to allow for transitions to the communal scene. - */ -@Composable -private fun BlankScene( - modifier: Modifier = Modifier, - hideSceneTransitionLayout: () -> Unit, -) { - Box(modifier.fillMaxSize()) { - Column( - Modifier.fillMaxHeight() - .width(ContainerDimensions.EdgeSwipeSize) - .align(Alignment.CenterEnd) - .background(Color(0x55e9f2eb)), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally + scene( + TransitionSceneKey.Communal, + userActions = + mapOf( + Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank + ), ) { - IconButton(onClick = hideSceneTransitionLayout) { - Icon(Icons.Filled.Close, contentDescription = "Close button") - } + CommunalScene(viewModel, modifier = modifier) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index d3d8e4ed3523..91a4d2e01e90 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -45,6 +45,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material.icons.outlined.TouchApp import androidx.compose.material.icons.outlined.Widgets import androidx.compose.material3.Button import androidx.compose.material3.ButtonColors @@ -76,17 +77,17 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView +import androidx.compose.ui.window.Popup import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel -import com.android.systemui.media.controls.ui.MediaHierarchyManager -import com.android.systemui.media.controls.ui.MediaHostState import com.android.systemui.res.R @Composable @@ -97,6 +98,8 @@ fun CommunalHub( onEditDone: (() -> Unit)? = null, ) { val communalContent by viewModel.communalContent.collectAsState(initial = emptyList()) + val isPopupOnDismissCtaShowing by + viewModel.isPopupOnDismissCtaShowing.collectAsState(initial = false) var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } var toolbarSize: IntSize? by remember { mutableStateOf(null) } var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } @@ -133,6 +136,10 @@ fun CommunalHub( } } + if (isPopupOnDismissCtaShowing) { + PopupOnDismissCtaTile(viewModel::onHidePopupAfterDismissCta) + } + // This spacer covers the edge of the LazyHorizontalGrid and prevents it from receiving // touches, so that the SceneTransitionLayout can intercept the touches and allow an edge // swipe back to the blank scene. @@ -319,8 +326,40 @@ private fun Toolbar( } @Composable +private fun PopupOnDismissCtaTile(onHidePopupAfterDismissCta: () -> Unit) { + Popup( + alignment = Alignment.TopCenter, + offset = IntOffset(0, 40), + onDismissRequest = onHidePopupAfterDismissCta + ) { + val colors = LocalAndroidColorScheme.current + Row( + modifier = + Modifier.height(56.dp) + .background(colors.secondary, RoundedCornerShape(50.dp)) + .padding(16.dp), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + imageVector = Icons.Outlined.TouchApp, + contentDescription = stringResource(R.string.popup_on_dismiss_cta_tile_text), + tint = colors.onSecondary, + modifier = Modifier.size(20.dp) + ) + Spacer(modifier = Modifier.size(8.dp)) + Text( + text = stringResource(R.string.popup_on_dismiss_cta_tile_text), + style = MaterialTheme.typography.titleSmall, + color = colors.onSecondary, + ) + } + } +} + +@Composable private fun RemoveButtonContent(spacerModifier: Modifier) { - Icon(Icons.Outlined.Delete, stringResource(R.string.button_to_open_widget_editor)) + Icon(Icons.Outlined.Delete, stringResource(R.string.button_to_remove_widget)) Spacer(spacerModifier) Text( text = stringResource(R.string.button_to_remove_widget), @@ -535,10 +574,6 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) AndroidView( modifier = modifier, factory = { - viewModel.mediaHost.expansion = MediaHostState.EXPANDED - viewModel.mediaHost.showsOnlyActiveMedia = false - viewModel.mediaHost.falsingProtectionNeeded = false - viewModel.mediaHost.init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB) viewModel.mediaHost.hostView.layoutParams = FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index 0eec024d3c81..0b26ae96de54 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -43,10 +43,7 @@ import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope -import com.android.compose.animation.scene.ValueKey -import com.android.compose.animation.scene.animateElementFloatAsState import com.android.systemui.notifications.ui.composable.Notifications.Form -import com.android.systemui.notifications.ui.composable.Notifications.SharedValues.SharedExpansionValue import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel object Notifications { @@ -56,10 +53,6 @@ object Notifications { val ShelfSpace = ElementKey("ShelfSpace") } - object SharedValues { - val SharedExpansionValue = ValueKey("SharedExpansionValue") - } - enum class Form { HunFromTop, Stack, @@ -181,13 +174,6 @@ private fun SceneScope.NotificationPlaceholder( ) } ) { - val animatedExpansion by - animateElementFloatAsState( - value = if (form == Form.HunFromTop) 0f else 1f, - key = SharedExpansionValue - ) - debugLog(viewModel) { "STACK composed: expansion=$animatedExpansion" } - content { if (viewModel.isPlaceholderTextVisible) { Box(Modifier.fillMaxSize()) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index 4eb9089dc589..c35202cd830a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -25,7 +25,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -38,11 +37,11 @@ import com.android.compose.animation.scene.Edge as SceneTransitionEdge import com.android.compose.animation.scene.ObservableTransitionState as SceneTransitionObservableTransitionState import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey import com.android.compose.animation.scene.SceneTransitionLayout -import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction import com.android.compose.animation.scene.observableTransitionState +import com.android.compose.animation.scene.updateSceneTransitionLayoutState import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.Edge @@ -82,7 +81,12 @@ fun SceneContainer( val currentScene = checkNotNull(sceneByKey[currentSceneKey]) val currentDestinations: Map<UserAction, SceneModel> by currentScene.destinationScenes.collectAsState() - val state = remember { SceneTransitionLayoutState(currentSceneKey.toTransitionSceneKey()) } + val state = + updateSceneTransitionLayoutState( + currentSceneKey.toTransitionSceneKey(), + onChangeScene = viewModel::onSceneChanged, + transitions = SceneContainerTransitions, + ) DisposableEffect(viewModel, state) { viewModel.setTransitionState(state.observableTransitionState().map { it.toModel() }) @@ -93,9 +97,6 @@ fun SceneContainer( modifier = Modifier.fillMaxSize(), ) { SceneTransitionLayout( - currentScene = currentSceneKey.toTransitionSceneKey(), - onChangeScene = viewModel::onSceneChanged, - transitions = SceneContainerTransitions, state = state, modifier = modifier diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt index ba6d00e3b7f5..7d3b0fbe1725 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt @@ -28,9 +28,9 @@ import kotlinx.coroutines.launch * the currently running transition, if there is one. */ internal fun CoroutineScope.animateToScene( - layoutState: SceneTransitionLayoutStateImpl, + layoutState: BaseSceneTransitionLayoutState, target: SceneKey, -) { +): TransitionState.Transition? { val transitionState = layoutState.transitionState if (transitionState.currentScene == target) { // This can happen in 3 different situations, for which there isn't anything else to do: @@ -41,10 +41,10 @@ internal fun CoroutineScope.animateToScene( // a. didn't release their pointer yet. // b. released their pointer such that the swipe gesture was cancelled and the // transition is currently animating back to [target]. - return + return null } - when (transitionState) { + return when (transitionState) { is TransitionState.Idle -> animate(layoutState, target) is TransitionState.Transition -> { // A transition is currently running: first check whether `transition.toScene` or @@ -62,47 +62,43 @@ internal fun CoroutineScope.animateToScene( // finish the current transition early to make sure that the current state // change is committed. layoutState.finishTransition(transitionState, transitionState.currentScene) + null } else { // The transition is in progress: start the canned animation at the same // progress as it was in. // TODO(b/290184746): Also take the current velocity into account. animate(layoutState, target, startProgress = progress) } - - return - } - - if (transitionState.fromScene == target) { + } else if (transitionState.fromScene == target) { // There is a transition from [target] to another scene: simply animate the same // transition progress to `0`. - check(transitionState.toScene == transitionState.currentScene) + val progress = transitionState.progress if (progress.absoluteValue < ProgressVisibilityThreshold) { // The transition is at progress ~= 0: no need to animate.We finish the current // transition early to make sure that the current state change is committed. layoutState.finishTransition(transitionState, transitionState.currentScene) + null } else { // TODO(b/290184746): Also take the current velocity into account. animate(layoutState, target, startProgress = progress, reversed = true) } - - return + } else { + // Generic interruption; the current transition is neither from or to [target]. + // TODO(b/290930950): Better handle interruptions here. + animate(layoutState, target) } - - // Generic interruption; the current transition is neither from or to [target]. - // TODO(b/290930950): Better handle interruptions here. - animate(layoutState, target) } } } private fun CoroutineScope.animate( - layoutState: SceneTransitionLayoutStateImpl, + layoutState: BaseSceneTransitionLayoutState, target: SceneKey, startProgress: Float = 0f, reversed: Boolean = false, -) { +): TransitionState.Transition { val fromScene = layoutState.transitionState.currentScene val isUserInput = (layoutState.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput @@ -143,10 +139,15 @@ private fun CoroutineScope.animate( } // Animate the progress to its target value. - launch { - animatable.animateTo(targetProgress, animationSpec) - layoutState.finishTransition(transition, target) - } + launch { animatable.animateTo(targetProgress, animationSpec) } + .invokeOnCompletion { + // Settle the state to Idle(target). Note that this will do nothing if this transition + // was replaced/interrupted by another one, and this also runs if this coroutine is + // cancelled, i.e. if [this] coroutine scope is cancelled. + layoutState.finishTransition(transition, target) + } + + return transition } private class OneOffTransition( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 280fbfb7d3d3..a910bca078e8 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -20,10 +20,10 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.geometry.isSpecified import androidx.compose.ui.geometry.isUnspecified import androidx.compose.ui.geometry.lerp import androidx.compose.ui.graphics.drawscope.ContentDrawScope @@ -46,41 +46,18 @@ import kotlinx.coroutines.launch /** An element on screen, that can be composed in one or more scenes. */ @Stable internal class Element(val key: ElementKey) { - /** - * The last state of this element, coming from any scene. Note that this state will be unstable - * if this element is present in multiple scenes but the shared element animation is disabled, - * given that multiple instances of the element with different states will write to this state. - * You should prefer using [SceneState.lastState] in the current scene when it is defined. - */ - val lastSharedState = State() - /** The mapping between a scene and the state this element has in that scene, if any. */ - val sceneStates = mutableMapOf<SceneKey, SceneState>() + // TODO(b/316901148): Make this a normal map instead once we can make sure that new transitions + // are first seen by composition then layout/drawing code. See 316901148#comment2 for details. + val sceneStates = SnapshotStateMap<SceneKey, SceneState>() override fun toString(): String { return "Element(key=$key)" } - /** The state of this element, either in a specific scene or in a shared context. */ - class State { - /** The offset of the element, relative to the SceneTransitionLayout containing it. */ - var offset = Offset.Unspecified - - /** The size of this element. */ - var size = SizeUnspecified - - /** The draw scale of this element. */ - var drawScale = Scale.Default - - /** The alpha of this element. */ - var alpha = AlphaUnspecified - } - /** The last and target state of this element in a given scene. */ @Stable class SceneState(val scene: SceneKey) { - val lastState = State() - var targetSize by mutableStateOf(SizeUnspecified) var targetOffset by mutableStateOf(Offset.Unspecified) @@ -94,7 +71,6 @@ internal class Element(val key: ElementKey) { companion object { val SizeUnspecified = IntSize(Int.MAX_VALUE, Int.MAX_VALUE) - val AlphaUnspecified = Float.MIN_VALUE } } @@ -219,7 +195,7 @@ internal class ElementNode( } override fun ContentDrawScope.draw() { - val drawScale = getDrawScale(layoutImpl, element, scene, sceneState) + val drawScale = getDrawScale(layoutImpl, element, scene) if (drawScale == Scale.Default) { drawContent() } else { @@ -264,7 +240,6 @@ private fun shouldDrawElement( // Always draw the element if there is no ongoing transition or if the element is not shared. if ( transition == null || - !layoutImpl.isTransitionReady(transition) || transition.fromScene !in element.sceneStates || transition.toScene !in element.sceneStates ) { @@ -304,7 +279,7 @@ internal fun shouldDrawOrComposeSharedElement( } private fun isSharedElementEnabled( - layoutState: SceneTransitionLayoutStateImpl, + layoutState: BaseSceneTransitionLayoutState, transition: TransitionState.Transition, element: ElementKey, ): Boolean { @@ -312,7 +287,7 @@ private fun isSharedElementEnabled( } internal fun sharedElementTransformation( - layoutState: SceneTransitionLayoutStateImpl, + layoutState: BaseSceneTransitionLayoutState, transition: TransitionState.Transition, element: ElementKey, ): SharedElementTransformation? { @@ -342,18 +317,9 @@ private fun isElementOpaque( layoutImpl: SceneTransitionLayoutImpl, element: Element, scene: Scene, - sceneState: Element.SceneState, ): Boolean { val transition = layoutImpl.state.currentTransition ?: return true - if (!layoutImpl.isTransitionReady(transition)) { - val lastValue = - sceneState.lastState.alpha.takeIf { it != Element.AlphaUnspecified } - ?: element.lastSharedState.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f - - return lastValue == 1f - } - val fromScene = transition.fromScene val toScene = transition.toScene val fromState = element.sceneStates[fromScene] @@ -383,7 +349,6 @@ private fun elementAlpha( layoutImpl: SceneTransitionLayoutImpl, element: Element, scene: Scene, - sceneState: Element.SceneState, ): Float { return computeValue( layoutImpl, @@ -393,10 +358,7 @@ private fun elementAlpha( transformation = { it.alpha }, idleValue = 1f, currentValue = { 1f }, - lastValue = { - sceneState.lastState.alpha.takeIf { it != Element.AlphaUnspecified } - ?: element.lastSharedState.alpha.takeIf { it != Element.AlphaUnspecified } ?: 1f - }, + isSpecified = { true }, ::lerp, ) .coerceIn(0f, 1f) @@ -434,34 +396,23 @@ private fun IntermediateMeasureScope.measure( transformation = { it.size }, idleValue = lookaheadSize, currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() }, - lastValue = { - sceneState.lastState.size.takeIf { it != Element.SizeUnspecified } - ?: element.lastSharedState.size.takeIf { it != Element.SizeUnspecified } - ?: measurable.measure(constraints).also { maybePlaceable = it }.size() - }, + isSpecified = { it != Element.SizeUnspecified }, ::lerp, ) - val placeable = - maybePlaceable - ?: measurable.measure( - Constraints.fixed( - targetSize.width.coerceAtLeast(0), - targetSize.height.coerceAtLeast(0), - ) + return maybePlaceable + ?: measurable.measure( + Constraints.fixed( + targetSize.width.coerceAtLeast(0), + targetSize.height.coerceAtLeast(0), ) - - val size = placeable.size() - element.lastSharedState.size = size - sceneState.lastState.size = size - return placeable + ) } private fun getDrawScale( layoutImpl: SceneTransitionLayoutImpl, element: Element, - scene: Scene, - sceneState: Element.SceneState + scene: Scene ): Scale { return computeValue( layoutImpl, @@ -471,10 +422,7 @@ private fun getDrawScale( transformation = { it.drawScale }, idleValue = Scale.Default, currentValue = { Scale.Default }, - lastValue = { - sceneState.lastState.drawScale.takeIf { it != Scale.Default } - ?: element.lastSharedState.drawScale - }, + isSpecified = { true }, ::lerp, ) } @@ -498,9 +446,12 @@ private fun IntermediateMeasureScope.place( sceneState.targetOffset = targetOffsetInScene } + // No need to place the element in this scene if we don't want to draw it anyways. + if (!shouldDrawElement(layoutImpl, scene, element)) { + return + } + val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) - val lastSharedState = element.lastSharedState - val lastSceneState = sceneState.lastState val targetOffset = computeValue( layoutImpl, @@ -510,37 +461,19 @@ private fun IntermediateMeasureScope.place( transformation = { it.offset }, idleValue = targetOffsetInScene, currentValue = { currentOffset }, - lastValue = { - lastSceneState.offset.takeIf { it.isSpecified } - ?: lastSharedState.offset.takeIf { it.isSpecified } ?: currentOffset - }, + isSpecified = { it != Offset.Unspecified }, ::lerp, ) - lastSharedState.offset = targetOffset - lastSceneState.offset = targetOffset - - // No need to place the element in this scene if we don't want to draw it anyways. Note that - // it's still important to compute the target offset and update last(Shared|Scene)State, - // otherwise they will be out of date. - if (!shouldDrawElement(layoutImpl, scene, element)) { - return - } - val offset = (targetOffset - currentOffset).round() - if (isElementOpaque(layoutImpl, element, scene, sceneState)) { + if (isElementOpaque(layoutImpl, element, scene)) { // TODO(b/291071158): Call placeWithLayer() if offset != IntOffset.Zero and size is not // animated once b/305195729 is fixed. Test that drawing is not invalidated in that // case. placeable.place(offset) - lastSharedState.alpha = 1f - lastSceneState.alpha = 1f } else { placeable.placeWithLayer(offset) { - val alpha = elementAlpha(layoutImpl, element, scene, sceneState) - this.alpha = alpha - lastSharedState.alpha = alpha - lastSceneState.alpha = alpha + this.alpha = elementAlpha(layoutImpl, element, scene) } } } @@ -563,8 +496,6 @@ private fun IntermediateMeasureScope.place( * different than [idleValue] even if the value is not transformed directly because it could be * impacted by the transformations on other elements, like a parent that is being translated or * resized. - * @param lastValue the last value that was used. This should be equal to [currentValue] if this is - * the first time the value is set. * @param lerp the linear interpolation function used to interpolate between two values of this * value type. */ @@ -576,7 +507,7 @@ private inline fun <T> computeValue( transformation: (ElementTransformations) -> PropertyTransformation<T>?, idleValue: T, currentValue: () -> T, - lastValue: () -> T, + isSpecified: (T) -> Boolean, lerp: (T, T, Float) -> T, ): T { val transition = @@ -587,21 +518,16 @@ private inline fun <T> computeValue( // layout phase. ?: return currentValue() - // A transition was started but it's not ready yet (not all elements have been composed/laid - // out yet). Use the last value that was set, to make sure elements don't unexpectedly jump. - if (!layoutImpl.isTransitionReady(transition)) { - return lastValue() - } - val fromScene = transition.fromScene val toScene = transition.toScene + val fromState = element.sceneStates[fromScene] val toState = element.sceneStates[toScene] if (fromState == null && toState == null) { // TODO(b/311600838): Throw an exception instead once layers of disposed elements are not // run anymore. - return lastValue() + return idleValue } // The element is shared: interpolate between the value in fromScene and the value in toScene. @@ -612,6 +538,11 @@ private inline fun <T> computeValue( val start = sceneValue(fromState!!) val end = sceneValue(toState!!) + // TODO(b/316901148): Remove checks to isSpecified() once the lookahead pass runs for all + // nodes before the intermediate layout pass. + if (!isSpecified(start)) return end + if (!isSpecified(end)) return start + // Make sure we don't read progress if values are the same and we don't need to interpolate, // so we don't invalidate the phase where this is read. return if (start == end) start else lerp(start, end, transition.progress) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt index af3c0999c97b..cdc4778dbf4d 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt @@ -174,22 +174,6 @@ private fun shouldComposeMovableElement( // If we are idle, there is only one [scene] that is composed so we can compose our // movable content here. ?: return true - val fromScene = transition.fromScene - val toScene = transition.toScene - - val fromReady = layoutImpl.isSceneReady(fromScene) - val toReady = layoutImpl.isSceneReady(toScene) - - if (!fromReady && !toReady) { - // Neither of the scenes will be drawn, so where we compose it doesn't really matter. Note - // that we could have slightly more complicated logic here to optimize for this case, but - // it's not worth it given that readyScenes should disappear soon (b/316901148). - return scene == toScene - } - - // If one of the scenes is not ready, compose it in the other one to make sure it is drawn. - if (!fromReady) return scene == toScene - if (!toReady) return scene == fromScene // Always compose movable elements in the scene picked by their scene picker. return shouldDrawOrComposeSharedElement( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt index 454c0ecf8ac5..b346a70e61f9 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt @@ -16,96 +16,118 @@ package com.android.compose.animation.scene +import androidx.compose.runtime.Stable import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size -import androidx.compose.ui.geometry.toRect import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.CompositingStrategy import androidx.compose.ui.graphics.Outline -import androidx.compose.ui.graphics.Paint import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.Shape import androidx.compose.ui.graphics.drawOutline import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.graphics.drawscope.DrawScope -import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.drawscope.translate -import androidx.compose.ui.graphics.withSaveLayer +import androidx.compose.ui.layout.LayoutCoordinates +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.DelegatingNode import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.GlobalPositionAwareModifierNode +import androidx.compose.ui.node.LayoutModifierNode import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.toSize -internal fun Modifier.punchHole( - layoutImpl: SceneTransitionLayoutImpl, - element: ElementKey, - bounds: ElementKey, - shape: Shape, -): Modifier = this.then(PunchHoleElement(layoutImpl, element, bounds, shape)) +/** + * Punch a hole in this node with the given [size], [offset] and [shape]. + * + * Punching a hole in an element will "remove" any pixel drawn by that element in the hole area. + * This can be used to make content drawn below an opaque element visible. For example, if we have + * [this lockscreen scene](http://shortn/_VYySFnJDhN) drawn below + * [this shade scene](http://shortn/_fpxGUk0Rg7) and punch a hole in the latter using the big clock + * time bounds and a RoundedCornerShape(10dp), [this](http://shortn/_qt80IvORFj) would be the + * result. + */ +@Stable +fun Modifier.punchHole( + size: () -> Size, + offset: () -> Offset, + shape: Shape = RectangleShape, +): Modifier = this.then(PunchHoleElement(size, offset, shape)) + +/** + * Punch a hole in this node using the bounds of [coords] and the given [shape]. + * + * You can use [androidx.compose.ui.layout.onGloballyPositioned] to get the last coordinates of a + * node. + */ +@Stable +fun Modifier.punchHole( + coords: () -> LayoutCoordinates?, + shape: Shape = RectangleShape, +): Modifier = this.then(PunchHoleWithBoundsElement(coords, shape)) private data class PunchHoleElement( - private val layoutImpl: SceneTransitionLayoutImpl, - private val element: ElementKey, - private val bounds: ElementKey, + private val size: () -> Size, + private val offset: () -> Offset, private val shape: Shape, ) : ModifierNodeElement<PunchHoleNode>() { - override fun create(): PunchHoleNode = PunchHoleNode(layoutImpl, element, bounds, shape) + override fun create(): PunchHoleNode = PunchHoleNode(size, offset, { shape }) override fun update(node: PunchHoleNode) { - node.layoutImpl = layoutImpl - node.element = element - node.bounds = bounds - node.shape = shape + node.size = size + node.offset = offset + node.shape = { shape } } } private class PunchHoleNode( - var layoutImpl: SceneTransitionLayoutImpl, - var element: ElementKey, - var bounds: ElementKey, - var shape: Shape, -) : Modifier.Node(), DrawModifierNode { + var size: () -> Size, + var offset: () -> Offset, + var shape: () -> Shape, +) : Modifier.Node(), DrawModifierNode, LayoutModifierNode { private var lastSize: Size = Size.Unspecified private var lastLayoutDirection: LayoutDirection = LayoutDirection.Ltr private var lastOutline: Outline? = null - override fun ContentDrawScope.draw() { - val bounds = layoutImpl.elements[bounds] - - if ( - bounds == null || - bounds.lastSharedState.size == Element.SizeUnspecified || - bounds.lastSharedState.offset == Offset.Unspecified - ) { - drawContent() - return + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints + ): MeasureResult { + return measurable.measure(constraints).run { + layout(width, height) { + placeWithLayer(0, 0) { compositingStrategy = CompositingStrategy.Offscreen } + } } + } - val element = layoutImpl.elements.getValue(element) - drawIntoCanvas { canvas -> - canvas.withSaveLayer(size.toRect(), Paint()) { - drawContent() + override fun ContentDrawScope.draw() { + drawContent() - val offset = bounds.lastSharedState.offset - element.lastSharedState.offset - translate(offset.x, offset.y) { drawHole(bounds) } - } + val holeSize = size() + if (holeSize != Size.Zero) { + val offset = offset() + translate(offset.x, offset.y) { drawHole(holeSize) } } } - private fun DrawScope.drawHole(bounds: Element) { - val boundsSize = bounds.lastSharedState.size.toSize() + private fun DrawScope.drawHole(size: Size) { if (shape == RectangleShape) { - drawRect(Color.Black, size = boundsSize, blendMode = BlendMode.DstOut) + drawRect(Color.Black, size = size, blendMode = BlendMode.DstOut) return } val outline = - if (boundsSize == lastSize && layoutDirection == lastLayoutDirection) { + if (size == lastSize && layoutDirection == lastLayoutDirection) { lastOutline!! } else { - val newOutline = shape.createOutline(boundsSize, layoutDirection, this) - lastSize = boundsSize + val newOutline = shape().createOutline(size, layoutDirection, this) + lastSize = size lastLayoutDirection = layoutDirection lastOutline = newOutline newOutline @@ -118,3 +140,39 @@ private class PunchHoleNode( ) } } + +private data class PunchHoleWithBoundsElement( + private val coords: () -> LayoutCoordinates?, + private val shape: Shape, +) : ModifierNodeElement<PunchHoleWithBoundsNode>() { + override fun create(): PunchHoleWithBoundsNode = PunchHoleWithBoundsNode(coords, shape) + + override fun update(node: PunchHoleWithBoundsNode) { + node.holeCoords = coords + node.shape = shape + } +} + +private class PunchHoleWithBoundsNode( + var holeCoords: () -> LayoutCoordinates?, + var shape: Shape, +) : DelegatingNode(), DrawModifierNode, GlobalPositionAwareModifierNode { + private val delegate = delegate(PunchHoleNode(::holeSize, ::holeOffset, ::shape)) + private var lastCoords: LayoutCoordinates? = null + + override fun onGloballyPositioned(coordinates: LayoutCoordinates) { + this.lastCoords = coordinates + } + + override fun ContentDrawScope.draw() = with(delegate) { draw() } + + private fun holeSize(): Size { + return holeCoords()?.size?.toSize() ?: Size.Zero + } + + private fun holeOffset(): Offset { + val holeCoords = holeCoords() ?: return Offset.Zero + val lastCoords = lastCoords ?: error("draw() was called before onGloballyPositioned()") + return lastCoords.localPositionOf(holeCoords, relativeToSource = Offset.Zero) + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt index 3537b7989ed5..f67df54b088c 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt @@ -26,7 +26,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Shape import androidx.compose.ui.layout.intermediateLayout import androidx.compose.ui.platform.testTag import androidx.compose.ui.unit.IntSize @@ -139,12 +138,6 @@ internal class SceneScopeImpl( bottomOrRightBehavior = bottomBehavior, ) - override fun Modifier.punchHole( - element: ElementKey, - bounds: ElementKey, - shape: Shape - ): Modifier = punchHole(layoutImpl, element, bounds, shape) - override fun Modifier.noResizeDuringTransitions(): Modifier { return noResizeDuringTransitions(layoutState = layoutImpl.state) } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt index 338557d0942e..64388b7653e0 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt @@ -312,13 +312,16 @@ internal class SceneGestureHandler( // immediately go back B => A. if (targetScene != swipeTransition._currentScene) { swipeTransition._currentScene = targetScene - layoutImpl.onChangeScene(targetScene.key) + with(layoutImpl.state) { coroutineScope.onChangeScene(targetScene.key) } } - animateOffset( + swipeTransition.animateOffset( + coroutineScope = coroutineScope, initialVelocity = velocity, targetOffset = targetOffset, - targetScene = targetScene.key + onAnimationCompleted = { + layoutState.finishTransition(swipeTransition, idleScene = targetScene.key) + } ) } @@ -410,34 +413,6 @@ internal class SceneGestureHandler( } } - private fun animateOffset( - initialVelocity: Float, - targetOffset: Float, - targetScene: SceneKey, - ) { - swipeTransition.startOffsetAnimation { - coroutineScope.launch { - if (!swipeTransition.isAnimatingOffset) { - swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset) - } - swipeTransition.isAnimatingOffset = true - - swipeTransition.offsetAnimatable.animateTo( - targetOffset, - // TODO(b/290184746): Make this spring spec configurable. - spring( - stiffness = Spring.StiffnessMediumLow, - visibilityThreshold = OffsetVisibilityThreshold - ), - initialVelocity = initialVelocity, - ) - - swipeTransition.finishOffsetAnimation() - layoutState.finishTransition(swipeTransition, targetScene) - } - } - } - internal class SwipeTransition( val _fromScene: Scene, val _toScene: Scene, @@ -479,12 +454,14 @@ internal class SceneGestureHandler( private var offsetAnimationJob: Job? = null /** Ends any previous [offsetAnimationJob] and runs the new [job]. */ - fun startOffsetAnimation(job: () -> Job) { + private fun startOffsetAnimation(job: () -> Job) { cancelOffsetAnimation() offsetAnimationJob = job() } /** Cancel any ongoing offset animation. */ + // TODO(b/317063114) This should be a suspended function to avoid multiple jobs running at + // the same time. fun cancelOffsetAnimation() { offsetAnimationJob?.cancel() finishOffsetAnimation() @@ -496,6 +473,43 @@ internal class SceneGestureHandler( dragOffset = offsetAnimatable.value } } + + // TODO(b/290184746): Make this spring spec configurable. + private val animationSpec = + spring( + stiffness = Spring.StiffnessMediumLow, + visibilityThreshold = OffsetVisibilityThreshold + ) + + fun animateOffset( + // TODO(b/317063114) The CoroutineScope should be removed. + coroutineScope: CoroutineScope, + initialVelocity: Float, + targetOffset: Float, + onAnimationCompleted: () -> Unit, + ) { + startOffsetAnimation { + coroutineScope.launch { + animateOffset(targetOffset, initialVelocity) + onAnimationCompleted() + } + } + } + + private suspend fun animateOffset(targetOffset: Float, initialVelocity: Float) { + if (!isAnimatingOffset) { + offsetAnimatable.snapTo(dragOffset) + } + isAnimatingOffset = true + + offsetAnimatable.animateTo( + targetValue = targetOffset, + animationSpec = animationSpec, + initialVelocity = initialVelocity, + ) + + finishOffsetAnimation() + } } companion object { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index 84fade8937ff..80f8c1c9e987 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -19,17 +19,48 @@ package com.android.compose.animation.scene import androidx.annotation.FloatRange import androidx.compose.foundation.gestures.Orientation import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Shape import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.platform.LocalDensity -import kotlinx.coroutines.channels.Channel + +/** + * [SceneTransitionLayout] is a container that automatically animates its content whenever its state + * changes. + * + * Note: You should use [androidx.compose.animation.AnimatedContent] instead of + * [SceneTransitionLayout] if it fits your need. Use [SceneTransitionLayout] over AnimatedContent if + * you need support for swipe gestures, shared elements or transitions defined declaratively outside + * UI code. + * + * @param state the state of this layout. + * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any. + * @param transitionInterceptionThreshold used during a scene transition. For the scene to be + * intercepted, the progress value must be above the threshold, and below (1 - threshold). + * @param scenes the configuration of the different scenes of this layout. + * @see updateSceneTransitionLayoutState + */ +@Composable +fun SceneTransitionLayout( + state: SceneTransitionLayoutState, + modifier: Modifier = Modifier, + edgeDetector: EdgeDetector = DefaultEdgeDetector, + @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f, + scenes: SceneTransitionLayoutScope.() -> Unit, +) { + SceneTransitionLayoutForTesting( + state, + modifier, + edgeDetector, + transitionInterceptionThreshold, + onLayoutImpl = null, + scenes, + ) +} /** * [SceneTransitionLayout] is a container that automatically animates its content whenever @@ -45,7 +76,6 @@ import kotlinx.coroutines.channels.Channel * This is called when the user commits a transition to a new scene because of a [UserAction], for * instance by triggering back navigation or by swiping to a new scene. * @param transitions the definition of the transitions used to animate a change of scene. - * @param state the observable state of this layout. * @param edgeDetector the edge detector used to detect which edge a swipe is started from, if any. * @param transitionInterceptionThreshold used during a scene transition. For the scene to be * intercepted, the progress value must be above the threshold, and below (1 - threshold). @@ -57,20 +87,16 @@ fun SceneTransitionLayout( onChangeScene: (SceneKey) -> Unit, transitions: SceneTransitions, modifier: Modifier = Modifier, - state: SceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) }, edgeDetector: EdgeDetector = DefaultEdgeDetector, @FloatRange(from = 0.0, to = 0.5) transitionInterceptionThreshold: Float = 0f, scenes: SceneTransitionLayoutScope.() -> Unit, ) { - SceneTransitionLayoutForTesting( - currentScene, - onChangeScene, - modifier, - transitions, + val state = updateSceneTransitionLayoutState(currentScene, onChangeScene, transitions) + SceneTransitionLayout( state, + modifier, edgeDetector, transitionInterceptionThreshold, - onLayoutImpl = null, scenes, ) } @@ -203,18 +229,6 @@ interface BaseSceneScope { ): Modifier /** - * Punch a hole in this [element] using the bounds of [bounds] in [scene] and the given [shape]. - * - * Punching a hole in an element will "remove" any pixel drawn by that element in the hole area. - * This can be used to make content drawn below an opaque element visible. For example, if we - * have [this lockscreen scene](http://shortn/_VYySFnJDhN) drawn below - * [this shade scene](http://shortn/_fpxGUk0Rg7) and punch a hole in the latter using the big - * clock time bounds and a RoundedCornerShape(10dp), [this](http://shortn/_qt80IvORFj) would be - * the result. - */ - fun Modifier.punchHole(element: ElementKey, bounds: ElementKey, shape: Shape): Modifier - - /** * Don't resize during transitions. This can for instance be used to make sure that scrollable * lists keep a constant size during transitions even if its elements are growing/shrinking. */ @@ -346,11 +360,8 @@ enum class SwipeDirection(val orientation: Orientation) { */ @Composable internal fun SceneTransitionLayoutForTesting( - currentScene: SceneKey, - onChangeScene: (SceneKey) -> Unit, + state: SceneTransitionLayoutState, modifier: Modifier = Modifier, - transitions: SceneTransitions = transitions {}, - state: SceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) }, edgeDetector: EdgeDetector = DefaultEdgeDetector, transitionInterceptionThreshold: Float = 0f, onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)? = null, @@ -360,8 +371,7 @@ internal fun SceneTransitionLayoutForTesting( val coroutineScope = rememberCoroutineScope() val layoutImpl = remember { SceneTransitionLayoutImpl( - state = state as SceneTransitionLayoutStateImpl, - onChangeScene = onChangeScene, + state = state as BaseSceneTransitionLayoutState, density = density, edgeDetector = edgeDetector, transitionInterceptionThreshold = transitionInterceptionThreshold, @@ -375,7 +385,6 @@ internal fun SceneTransitionLayoutForTesting( // SnapshotStateMap anymore. layoutImpl.updateScenes(scenes) - val targetSceneChannel = remember { Channel<SceneKey>(Channel.CONFLATED) } SideEffect { if (state != layoutImpl.state) { error( @@ -384,23 +393,8 @@ internal fun SceneTransitionLayoutForTesting( ) } - layoutImpl.onChangeScene = onChangeScene - (state as SceneTransitionLayoutStateImpl).transitions = transitions layoutImpl.density = density layoutImpl.edgeDetector = edgeDetector - - state.transitions = transitions - - targetSceneChannel.trySend(currentScene) - } - - LaunchedEffect(targetSceneChannel) { - for (newKey in targetSceneChannel) { - // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame - // late. - val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey - animateToScene(layoutImpl.state, newKey) - } } layoutImpl.Content(modifier) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index 0227aba94b53..7cc9d2623e9c 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -20,14 +20,11 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.key import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.layout.LookaheadScope import androidx.compose.ui.layout.intermediateLayout import androidx.compose.ui.unit.Density @@ -48,13 +45,12 @@ internal typealias MovableElementContent = @Stable internal class SceneTransitionLayoutImpl( - internal val state: SceneTransitionLayoutStateImpl, - internal var onChangeScene: (SceneKey) -> Unit, + internal val state: BaseSceneTransitionLayoutState, internal var density: Density, internal var edgeDetector: EdgeDetector, internal var transitionInterceptionThreshold: Float, builder: SceneTransitionLayoutScope.() -> Unit, - coroutineScope: CoroutineScope, + private val coroutineScope: CoroutineScope, ) { /** * The map of [Scene]s. @@ -100,16 +96,6 @@ internal class SceneTransitionLayoutImpl( ?: mutableMapOf<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>() .also { _sharedValues = it } - /** - * The scenes that are "ready", i.e. they were composed and fully laid-out at least once. - * - * Note that this map is *read* during composition, so it is a [SnapshotStateMap] to make sure - * that we recompose when modifications are made to this map. - * - * TODO(b/316901148): Remove this map. - */ - private val readyScenes = SnapshotStateMap<SceneKey, Boolean>() - private val horizontalGestureHandler: SceneGestureHandler private val verticalGestureHandler: SceneGestureHandler @@ -244,49 +230,19 @@ internal class SceneTransitionLayoutImpl( // TODO(b/290184746): Make sure that this works with SystemUI once we use // SceneTransitionLayout in Flexiglass. scene(state.transitionState.currentScene).userActions[Back]?.let { backScene -> - BackHandler { onChangeScene(backScene) } + BackHandler { with(state) { coroutineScope.onChangeScene(backScene) } } } Box { scenesToCompose.fastForEach { scene -> val key = scene.key - key(key) { - // Mark this scene as ready once it has been composed, laid out and - // drawn the first time. We have to do this in a LaunchedEffect here - // because DisposableEffect runs between composition and layout. - LaunchedEffect(key) { readyScenes[key] = true } - DisposableEffect(key) { onDispose { readyScenes.remove(key) } } - - scene.Content( - Modifier.drawWithContent { - if (state.currentTransition == null) { - drawContent() - } else { - // Don't draw scenes that are not ready yet. - if (readyScenes.containsKey(key)) { - drawContent() - } - } - } - ) - } + key(key) { scene.Content() } } } } } } - /** - * Return whether [transition] is ready, i.e. the elements of both scenes of the transition were - * laid out at least once. - */ - internal fun isTransitionReady(transition: TransitionState.Transition): Boolean { - return readyScenes.containsKey(transition.fromScene) && - readyScenes.containsKey(transition.toScene) - } - - internal fun isSceneReady(scene: SceneKey): Boolean = readyScenes.containsKey(scene) - internal fun setScenesTargetSizeForTest(size: IntSize) { scenes.values.forEach { it.targetSize = size } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index 0607aa148157..956e326dc03e 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -16,12 +16,23 @@ package com.android.compose.animation.scene +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel -/** The state of a [SceneTransitionLayout]. */ +/** + * The state of a [SceneTransitionLayout]. + * + * @see MutableSceneTransitionLayoutState + * @see updateSceneTransitionLayoutState + */ @Stable sealed interface SceneTransitionLayoutState { /** @@ -36,6 +47,9 @@ sealed interface SceneTransitionLayoutState { val currentTransition: TransitionState.Transition? get() = transitionState as? TransitionState.Transition + /** The [SceneTransitions] used when animating this state. */ + val transitions: SceneTransitions + /** * Whether we are transitioning. If [from] or [to] is empty, we will also check that they match * the scenes we are animating from and/or to. @@ -46,9 +60,68 @@ sealed interface SceneTransitionLayoutState { fun isTransitioningBetween(scene: SceneKey, other: SceneKey): Boolean } -/** Create a new [SceneTransitionLayoutState] that is currently idle at scene [currentScene]. */ -fun SceneTransitionLayoutState(currentScene: SceneKey): SceneTransitionLayoutState { - return SceneTransitionLayoutStateImpl(currentScene, SceneTransitions.Empty) +/** A [SceneTransitionLayoutState] whose target scene can be imperatively set. */ +sealed interface MutableSceneTransitionLayoutState : SceneTransitionLayoutState { + /** The [SceneTransitions] used when animating this state. */ + override var transitions: SceneTransitions + + /** + * Set the target scene of this state to [targetScene]. + * + * If [targetScene] is the same as the [currentScene][TransitionState.currentScene] of + * [transitionState], then nothing will happen and this will return `null`. Note that this means + * that this will also do nothing if the user is currently swiping from [targetScene] to another + * scene, or if we were already animating to [targetScene]. + * + * If [targetScene] is different than the [currentScene][TransitionState.currentScene] of + * [transitionState], then this will animate to [targetScene]. The associated + * [TransitionState.Transition] will be returned and will be set as the current + * [transitionState] of this [MutableSceneTransitionLayoutState]. + * + * Note that because a non-null [TransitionState.Transition] is returned does not mean that the + * transition will finish and that we will settle to [targetScene]. The returned transition + * might still be interrupted, for instance by another call to [setTargetScene] or by a user + * gesture. + * + * If [this] [CoroutineScope] is cancelled during the transition and that the transition was + * still active, then the [transitionState] of this [MutableSceneTransitionLayoutState] will be + * set to `TransitionState.Idle(targetScene)`. + * + * TODO(b/318794193): Add APIs to await() and cancel() any [TransitionState.Transition]. + */ + fun setTargetScene( + targetScene: SceneKey, + coroutineScope: CoroutineScope, + ): TransitionState.Transition? +} + +/** Return a [MutableSceneTransitionLayoutState] initially idle at [initialScene]. */ +fun MutableSceneTransitionLayoutState( + initialScene: SceneKey, + transitions: SceneTransitions = SceneTransitions.Empty, +): MutableSceneTransitionLayoutState { + return MutableSceneTransitionLayoutStateImpl(initialScene, transitions) +} + +/** + * Sets up a [SceneTransitionLayoutState] and keeps it synced with [currentScene], [onChangeScene] + * and [transitions]. New transitions will automatically be started whenever [currentScene] is + * changed. + * + * @param currentScene the current scene + * @param onChangeScene a mutator that should set [currentScene] to the given scene when called. + * This is called when the user commits a transition to a new scene because of a [UserAction], for + * instance by triggering back navigation or by swiping to a new scene. + * @param transitions the definition of the transitions used to animate a change of scene. + */ +@Composable +fun updateSceneTransitionLayoutState( + currentScene: SceneKey, + onChangeScene: (SceneKey) -> Unit, + transitions: SceneTransitions = SceneTransitions.Empty, +): SceneTransitionLayoutState { + return remember { HoistedSceneTransitionLayoutScene(currentScene, transitions, onChangeScene) } + .apply { update(currentScene, onChangeScene, transitions) } } @Stable @@ -109,13 +182,11 @@ sealed interface TransitionState { } } -internal class SceneTransitionLayoutStateImpl( - initialScene: SceneKey, - internal var transitions: SceneTransitions, -) : SceneTransitionLayoutState { +internal abstract class BaseSceneTransitionLayoutState(initialScene: SceneKey) : + SceneTransitionLayoutState { override var transitionState: TransitionState by mutableStateOf(TransitionState.Idle(initialScene)) - private set + protected set /** * The current [transformationSpec] associated to [transitionState]. Accessing this value makes @@ -123,6 +194,14 @@ internal class SceneTransitionLayoutStateImpl( */ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty + /** + * Called when the [current scene][TransitionState.currentScene] should be changed to [scene]. + * + * When this is called, the source of truth for the current scene should be changed so that + * [transitionState] will animate and settle to [scene]. + */ + internal abstract fun CoroutineScope.onChangeScene(scene: SceneKey) + override fun isTransitioning(from: SceneKey?, to: SceneKey?): Boolean { val transition = currentTransition ?: return false return transition.isTransitioning(from, to) @@ -154,3 +233,62 @@ internal class SceneTransitionLayoutStateImpl( } } } + +/** + * A [SceneTransitionLayout] whose current scene/source of truth is hoisted (its current value comes + * from outside). + */ +internal class HoistedSceneTransitionLayoutScene( + initialScene: SceneKey, + override var transitions: SceneTransitions, + private var changeScene: (SceneKey) -> Unit, +) : BaseSceneTransitionLayoutState(initialScene) { + private val targetSceneChannel = Channel<SceneKey>(Channel.CONFLATED) + + override fun CoroutineScope.onChangeScene(scene: SceneKey) = changeScene(scene) + + @Composable + fun update( + currentScene: SceneKey, + onChangeScene: (SceneKey) -> Unit, + transitions: SceneTransitions, + ) { + SideEffect { + this.changeScene = onChangeScene + this.transitions = transitions + + targetSceneChannel.trySend(currentScene) + } + + LaunchedEffect(targetSceneChannel) { + for (newKey in targetSceneChannel) { + // Inspired by AnimateAsState.kt: let's poll the last value to avoid being one frame + // late. + val newKey = targetSceneChannel.tryReceive().getOrNull() ?: newKey + animateToScene(layoutState = this@HoistedSceneTransitionLayoutScene, newKey) + } + } + } +} + +/** A [MutableSceneTransitionLayoutState] that holds the value for the current scene. */ +internal class MutableSceneTransitionLayoutStateImpl( + initialScene: SceneKey, + override var transitions: SceneTransitions, +) : MutableSceneTransitionLayoutState, BaseSceneTransitionLayoutState(initialScene) { + override fun setTargetScene( + targetScene: SceneKey, + coroutineScope: CoroutineScope + ): TransitionState.Transition? { + return with(this) { + coroutineScope.animateToScene( + layoutState = this@MutableSceneTransitionLayoutStateImpl, + target = targetScene, + ) + } + } + + override fun CoroutineScope.onChangeScene(scene: SceneKey) { + setTargetScene(scene, coroutineScope = this) + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index 35a5054cbd2a..c0de87abbfe8 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -16,7 +16,6 @@ package com.android.compose.animation.scene -import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box @@ -35,17 +34,11 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.layout.intermediateLayout -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.test.junit4.createComposeRule -import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.android.compose.test.subjects.DpOffsetSubject -import com.android.compose.test.subjects.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -263,8 +256,11 @@ class ElementTest { rule.setContent { SceneTransitionLayoutForTesting( - currentScene = currentScene, - onChangeScene = { currentScene = it }, + state = + updateSceneTransitionLayoutState( + currentScene = currentScene, + onChangeScene = { currentScene = it } + ), onLayoutImpl = { nullableLayoutImpl = it }, ) { scene(TestScenes.SceneA) { /* Nothing */} @@ -428,8 +424,11 @@ class ElementTest { rule.setContent { SceneTransitionLayoutForTesting( - currentScene = TestScenes.SceneA, - onChangeScene = {}, + state = + updateSceneTransitionLayoutState( + currentScene = TestScenes.SceneA, + onChangeScene = {} + ), onLayoutImpl = { nullableLayoutImpl = it }, ) { scene(TestScenes.SceneA) { Box(Modifier.element(key)) } @@ -478,8 +477,11 @@ class ElementTest { scrollScope = rememberCoroutineScope() SceneTransitionLayoutForTesting( - currentScene = TestScenes.SceneA, - onChangeScene = {}, + state = + updateSceneTransitionLayoutState( + currentScene = TestScenes.SceneA, + onChangeScene = {} + ), onLayoutImpl = { nullableLayoutImpl = it }, ) { scene(TestScenes.SceneA) { @@ -565,86 +567,4 @@ class ElementTest { after { assertThat(fooCompositions).isEqualTo(1) } } } - - @Test - fun sharedElementOffsetIsUpdatedEvenWhenNotPlaced() { - var nullableLayoutImpl: SceneTransitionLayoutImpl? = null - var density: Density? = null - - fun layoutImpl() = nullableLayoutImpl ?: error("nullableLayoutImpl was not set") - - fun density() = density ?: error("density was not set") - - fun Offset.toDpOffset() = with(density()) { DpOffset(x.toDp(), y.toDp()) } - - fun foo() = layoutImpl().elements[TestElements.Foo] ?: error("Foo not in elements map") - - fun Element.lastSharedOffset() = lastSharedState.offset.toDpOffset() - - fun Element.lastOffsetIn(scene: SceneKey) = - (sceneStates[scene] ?: error("$scene not in sceneValues map")) - .lastState - .offset - .toDpOffset() - - rule.testTransition( - from = TestScenes.SceneA, - to = TestScenes.SceneB, - transitionLayout = { currentScene, onChangeScene -> - density = LocalDensity.current - - SceneTransitionLayoutForTesting( - currentScene = currentScene, - onChangeScene = onChangeScene, - onLayoutImpl = { nullableLayoutImpl = it }, - transitions = - transitions { - from(TestScenes.SceneA, to = TestScenes.SceneB) { - spec = tween(durationMillis = 4 * 16, easing = LinearEasing) - } - } - ) { - scene(TestScenes.SceneA) { Box(Modifier.element(TestElements.Foo)) } - scene(TestScenes.SceneB) { - Box(Modifier.offset(x = 40.dp, y = 80.dp).element(TestElements.Foo)) - } - } - } - ) { - val tolerance = DpOffsetSubject.DefaultTolerance - - before { - val expected = DpOffset(0.dp, 0.dp) - assertThat(foo().lastSharedOffset()).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneA)).isWithin(tolerance).of(expected) - } - - at(16) { - val expected = DpOffset(10.dp, 20.dp) - assertThat(foo().lastSharedOffset()).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneA)).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneB)).isWithin(tolerance).of(expected) - } - - at(32) { - val expected = DpOffset(20.dp, 40.dp) - assertThat(foo().lastSharedOffset()).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneA)).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneB)).isWithin(tolerance).of(expected) - } - - at(48) { - val expected = DpOffset(30.dp, 60.dp) - assertThat(foo().lastSharedOffset()).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneA)).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneB)).isWithin(tolerance).of(expected) - } - - after { - val expected = DpOffset(40.dp, 80.dp) - assertThat(foo().lastSharedOffset()).isWithin(tolerance).of(expected) - assertThat(foo().lastOffsetIn(TestScenes.SceneB)).isWithin(tolerance).of(expected) - } - } - } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt index 04b3f8a1dfe7..0f9b0249b93f 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ObservableTransitionStateTest.kt @@ -32,7 +32,7 @@ class ObservableTransitionStateTest { @Test fun testObservableTransitionState() = runTest { - val state = SceneTransitionLayoutState(TestScenes.SceneA) + lateinit var state: SceneTransitionLayoutState // Collect the current observable state into [observableState]. // TODO(b/290184746): Use collectValues {} once it is extracted into a library that can be @@ -58,12 +58,14 @@ class ObservableTransitionStateTest { from = TestScenes.SceneA, to = TestScenes.SceneB, transitionLayout = { currentScene, onChangeScene -> - SceneTransitionLayout( - currentScene, - onChangeScene, - EmptyTestTransitions, - state = state, - ) { + state = + updateSceneTransitionLayoutState( + currentScene, + onChangeScene, + EmptyTestTransitions + ) + + SceneTransitionLayout(state = state) { scene(TestScenes.SceneA) {} scene(TestScenes.SceneB) {} } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt index d9ce5191f3d9..066a3e45fb3c 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt @@ -18,9 +18,6 @@ package com.android.compose.animation.scene import androidx.compose.foundation.gestures.Orientation import androidx.compose.material3.Text -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource @@ -53,10 +50,8 @@ class SceneGestureHandlerTest { private class TestGestureScope( val coroutineScope: MonotonicClockTestScope, ) { - private var internalCurrentScene: SceneKey by mutableStateOf(SceneA) - private val layoutState = - SceneTransitionLayoutStateImpl(internalCurrentScene, EmptyTestTransitions) + MutableSceneTransitionLayoutStateImpl(SceneA, EmptyTestTransitions) val mutableUserActionsA: MutableMap<UserAction, SceneKey> = mutableMapOf(Swipe.Up to SceneB, Swipe.Down to SceneC) @@ -94,7 +89,6 @@ class SceneGestureHandlerTest { private val layoutImpl = SceneTransitionLayoutImpl( state = layoutState, - onChangeScene = { internalCurrentScene = it }, density = Density(1f), edgeDetector = DefaultEdgeDetector, transitionInterceptionThreshold = transitionInterceptionThreshold, diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index 75dee47a91cd..48825fb88096 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -18,7 +18,11 @@ package com.android.compose.animation.scene import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.compose.test.runMonotonicClockTest import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -29,7 +33,7 @@ class SceneTransitionLayoutStateTest { @Test fun isTransitioningTo_idle() { - val state = SceneTransitionLayoutState(TestScenes.SceneA) + val state = MutableSceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty) assertThat(state.isTransitioning()).isFalse() assertThat(state.isTransitioning(from = TestScenes.SceneA)).isFalse() @@ -40,7 +44,7 @@ class SceneTransitionLayoutStateTest { @Test fun isTransitioningTo_transition() { - val state = SceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty) + val state = MutableSceneTransitionLayoutStateImpl(TestScenes.SceneA, SceneTransitions.Empty) state.startTransition(transition(from = TestScenes.SceneA, to = TestScenes.SceneB)) assertThat(state.isTransitioning()).isTrue() @@ -50,4 +54,56 @@ class SceneTransitionLayoutStateTest { assertThat(state.isTransitioning(to = TestScenes.SceneA)).isFalse() assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue() } + + @Test + fun setTargetScene_idleToSameScene() = runMonotonicClockTest { + val state = MutableSceneTransitionLayoutState(TestScenes.SceneA) + assertThat(state.setTargetScene(TestScenes.SceneA, coroutineScope = this)).isNull() + } + + @Test + fun setTargetScene_idleToDifferentScene() = runMonotonicClockTest { + val state = MutableSceneTransitionLayoutState(TestScenes.SceneA) + val transition = state.setTargetScene(TestScenes.SceneB, coroutineScope = this) + assertThat(transition).isNotNull() + assertThat(state.transitionState).isEqualTo(transition) + + testScheduler.advanceUntilIdle() + assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB)) + } + + @Test + fun setTargetScene_transitionToSameScene() = runMonotonicClockTest { + val state = MutableSceneTransitionLayoutState(TestScenes.SceneA) + assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull() + assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNull() + testScheduler.advanceUntilIdle() + assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB)) + } + + @Test + fun setTargetScene_transitionToDifferentScene() = runMonotonicClockTest { + val state = MutableSceneTransitionLayoutState(TestScenes.SceneA) + assertThat(state.setTargetScene(TestScenes.SceneB, coroutineScope = this)).isNotNull() + assertThat(state.setTargetScene(TestScenes.SceneC, coroutineScope = this)).isNotNull() + testScheduler.advanceUntilIdle() + assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneC)) + } + + @Test + fun setTargetScene_coroutineScopeCancelled() = runMonotonicClockTest { + val state = MutableSceneTransitionLayoutState(TestScenes.SceneA) + + lateinit var transition: TransitionState.Transition + val job = + launch(start = CoroutineStart.UNDISPATCHED) { + transition = state.setTargetScene(TestScenes.SceneB, coroutineScope = this)!! + } + assertThat(state.transitionState).isEqualTo(transition) + + // Cancelling the scope/job still sets the state to Idle(targetScene). + job.cancel() + testScheduler.advanceUntilIdle() + assertThat(state.transitionState).isEqualTo(TransitionState.Idle(TestScenes.SceneB)) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt index 649e4991434e..efaea71f8d2c 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt @@ -63,7 +63,7 @@ class SceneTransitionLayoutTest { } private var currentScene by mutableStateOf(TestScenes.SceneA) - private val layoutState = SceneTransitionLayoutState(currentScene) + private lateinit var layoutState: SceneTransitionLayoutState // We use createAndroidComposeRule() here and not createComposeRule() because we need an // activity for testBack(). @@ -72,10 +72,14 @@ class SceneTransitionLayoutTest { /** The content under test. */ @Composable private fun TestContent() { + layoutState = + updateSceneTransitionLayoutState( + currentScene, + { currentScene = it }, + EmptyTestTransitions + ) + SceneTransitionLayout( - currentScene, - { currentScene = it }, - EmptyTestTransitions, state = layoutState, modifier = Modifier.size(LayoutSize), ) { diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index 58d853ef5a00..1ec3c8ba2301 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -20,9 +20,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.platform.LocalViewConfiguration @@ -58,18 +55,15 @@ class SwipeToSceneTest { get() = Offset(0f, (LayoutHeight / 2).toPx()) } - private var currentScene by mutableStateOf(TestScenes.SceneA) - private val layoutState = SceneTransitionLayoutState(currentScene) - @get:Rule val rule = createComposeRule() + private fun layoutState(initialScene: SceneKey = TestScenes.SceneA) = + MutableSceneTransitionLayoutState(initialScene, EmptyTestTransitions) + /** The content under test. */ @Composable - private fun TestContent() { + private fun TestContent(layoutState: SceneTransitionLayoutState) { SceneTransitionLayout( - currentScene, - { currentScene = it }, - EmptyTestTransitions, state = layoutState, modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName), ) { @@ -109,9 +103,11 @@ class SwipeToSceneTest { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f + + val layoutState = layoutState() rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - TestContent() + TestContent(layoutState) } assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java) @@ -195,9 +191,10 @@ class SwipeToSceneTest { // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f + val layoutState = layoutState() rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - TestContent() + TestContent(layoutState) } assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java) @@ -260,14 +257,14 @@ class SwipeToSceneTest { @Test fun multiPointerSwipe() { // Start at scene C. - currentScene = TestScenes.SceneC + val layoutState = layoutState(TestScenes.SceneC) // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - TestContent() + TestContent(layoutState) } assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java) @@ -299,14 +296,14 @@ class SwipeToSceneTest { @Test fun defaultEdgeSwipe() { // Start at scene C. - currentScene = TestScenes.SceneC + val layoutState = layoutState(TestScenes.SceneC) // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is // detected as a drag event. var touchSlop = 0f rule.setContent { touchSlop = LocalViewConfiguration.current.touchSlop - TestContent() + TestContent(layoutState) } assertThat(layoutState.transitionState).isInstanceOf(TransitionState.Idle::class.java) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt index cb122dc8e25e..fbcd5b27836e 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/test/RunMonotonicClockTest.kt @@ -13,7 +13,7 @@ import kotlinx.coroutines.withContext * * The [TestCoroutineScheduler] is passed to provide the functionality to wait for idle. */ -@ExperimentalTestApi +@OptIn(ExperimentalTestApi::class) fun runMonotonicClockTest(block: suspend MonotonicClockTestScope.() -> Unit) = runTest { // We need a CoroutineScope (like a TestScope) to create a TestMonotonicFrameClock. withContext(TestMonotonicFrameClock(this)) { diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt index 41bde5298c66..3dfe65a4f736 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockRegistry.kt @@ -22,6 +22,7 @@ import android.net.Uri import android.os.UserHandle import android.provider.Settings import androidx.annotation.OpenForTesting +import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.LogLevel import com.android.systemui.log.core.LogcatOnlyMessageBuffer import com.android.systemui.log.core.Logger @@ -120,8 +121,9 @@ open class ClockRegistry( override fun onPluginAttached( manager: PluginLifecycleManager<ClockProviderPlugin> ): Boolean { - manager.isDebug = !keepAllLoaded - + manager.setLogFunc({ tag, msg -> + (clockBuffers?.infraMessageBuffer as LogBuffer?)?.log(tag, LogLevel.DEBUG, msg) + }) if (keepAllLoaded) { // Always load new plugins if requested return true diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt index c8461d2c5415..02d30c5ea20a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt @@ -197,7 +197,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() { whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(true) featureFlags = FakeFeatureFlags() - featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false) featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false) featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false) diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt index cbcca55f6a34..f7751753cc18 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSimPinViewControllerTest.kt @@ -100,9 +100,12 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { mSelectedUserInteractor ) underTest.init() + underTest.onViewAttached() underTest.onResume(0) verify(keyguardUpdateMonitor) .registerCallback(updateMonitorCallbackArgumentCaptor.capture()) + reset(keyguardMessageAreaController) + reset(keyguardUpdateMonitor) } @Test @@ -110,25 +113,24 @@ class KeyguardSimPinViewControllerTest : SysuiTestCase() { underTest.onViewAttached() verify(keyguardMessageAreaController) .setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false) + verify(keyguardUpdateMonitor) + .registerCallback(any(KeyguardUpdateMonitorCallback::class.java)) } @Test fun onViewDetached() { underTest.onViewDetached() + verify(keyguardUpdateMonitor).removeCallback(any(KeyguardUpdateMonitorCallback::class.java)) } @Test fun onResume() { - reset(keyguardUpdateMonitor) underTest.onResume(KeyguardSecurityView.VIEW_REVEALED) - verify(keyguardUpdateMonitor) - .registerCallback(any(KeyguardUpdateMonitorCallback::class.java)) } @Test fun onPause() { underTest.onPause() - verify(keyguardUpdateMonitor).removeCallback(any(KeyguardUpdateMonitorCallback::class.java)) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt index 74f50d8c844b..27d1eb741bb0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorCorrectionRepositoryImplTest.kt @@ -37,11 +37,9 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ColorCorrectionRepositoryImplTest : SysuiTestCase() { - companion object { - val TEST_USER_1 = UserHandle.of(1)!! - val TEST_USER_2 = UserHandle.of(2)!! - } + private val testUser1 = UserHandle.of(1)!! + private val testUser2 = UserHandle.of(2)!! private val testDispatcher = StandardTestDispatcher() private val scope = TestScope(testDispatcher) private val settings: FakeSettings = FakeSettings() @@ -63,7 +61,7 @@ class ColorCorrectionRepositoryImplTest : SysuiTestCase() { settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, 1, - TEST_USER_1.identifier + testUser1.identifier ) underTest = @@ -72,84 +70,84 @@ class ColorCorrectionRepositoryImplTest : SysuiTestCase() { settings, ) - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) + underTest.isEnabled(testUser1).launchIn(backgroundScope) runCurrent() - val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first() + val actualValue: Boolean = underTest.isEnabled(testUser1).first() Truth.assertThat(actualValue).isTrue() } @Test fun isEnabled_settingUpdated_valueUpdated() = scope.runTest { - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) + underTest.isEnabled(testUser1).launchIn(backgroundScope) settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.DISABLED, - TEST_USER_1.identifier + testUser1.identifier ) runCurrent() - Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() + Truth.assertThat(underTest.isEnabled(testUser1).first()).isFalse() settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.ENABLED, - TEST_USER_1.identifier + testUser1.identifier ) runCurrent() - Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue() + Truth.assertThat(underTest.isEnabled(testUser1).first()).isTrue() settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.DISABLED, - TEST_USER_1.identifier + testUser1.identifier ) runCurrent() - Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() + Truth.assertThat(underTest.isEnabled(testUser1).first()).isFalse() } @Test fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() = scope.runTest { - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) + underTest.isEnabled(testUser1).launchIn(backgroundScope) settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.DISABLED, - TEST_USER_1.identifier + testUser1.identifier ) - underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope) + underTest.isEnabled(testUser2).launchIn(backgroundScope) settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.DISABLED, - TEST_USER_2.identifier + testUser2.identifier ) runCurrent() - Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() - Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse() + Truth.assertThat(underTest.isEnabled(testUser1).first()).isFalse() + Truth.assertThat(underTest.isEnabled(testUser2).first()).isFalse() settings.putIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, ColorCorrectionRepositoryImpl.ENABLED, - TEST_USER_1.identifier + testUser1.identifier ) runCurrent() - Truth.assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue() - Truth.assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse() + Truth.assertThat(underTest.isEnabled(testUser1).first()).isTrue() + Truth.assertThat(underTest.isEnabled(testUser2).first()).isFalse() } @Test fun setEnabled() = scope.runTest { - val success = underTest.setIsEnabled(true, TEST_USER_1) + val success = underTest.setIsEnabled(true, testUser1) runCurrent() Truth.assertThat(success).isTrue() val actualValue = settings.getIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, - TEST_USER_1.identifier + testUser1.identifier ) Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.ENABLED) } @@ -157,14 +155,14 @@ class ColorCorrectionRepositoryImplTest : SysuiTestCase() { @Test fun setDisabled() = scope.runTest { - val success = underTest.setIsEnabled(false, TEST_USER_1) + val success = underTest.setIsEnabled(false, testUser1) runCurrent() Truth.assertThat(success).isTrue() val actualValue = settings.getIntForUser( ColorCorrectionRepositoryImpl.SETTING_NAME, - TEST_USER_1.identifier + testUser1.identifier ) Truth.assertThat(actualValue).isEqualTo(ColorCorrectionRepositoryImpl.DISABLED) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt index 3f05fef3c141..423e124bbc84 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt @@ -39,6 +39,8 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class ColorInversionRepositoryImplTest : SysuiTestCase() { + private val testUser1 = UserHandle.of(1)!! + private val testUser2 = UserHandle.of(2)!! private val testDispatcher = StandardTestDispatcher() private val scope = TestScope(testDispatcher) private val settings: FakeSettings = FakeSettings() @@ -57,7 +59,7 @@ class ColorInversionRepositoryImplTest : SysuiTestCase() { @Test fun isEnabled_initiallyGetsSettingsValue() = scope.runTest { - settings.putIntForUser(SETTING_NAME, 1, TEST_USER_1.identifier) + settings.putIntForUser(SETTING_NAME, 1, testUser1.identifier) underTest = ColorInversionRepositoryImpl( @@ -65,68 +67,68 @@ class ColorInversionRepositoryImplTest : SysuiTestCase() { settings, ) - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) + underTest.isEnabled(testUser1).launchIn(backgroundScope) runCurrent() - val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first() + val actualValue: Boolean = underTest.isEnabled(testUser1).first() assertThat(actualValue).isTrue() } @Test fun isEnabled_settingUpdated_valueUpdated() = scope.runTest { - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) + underTest.isEnabled(testUser1).launchIn(backgroundScope) - settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier) + settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier) runCurrent() - assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() + assertThat(underTest.isEnabled(testUser1).first()).isFalse() - settings.putIntForUser(SETTING_NAME, ENABLED, TEST_USER_1.identifier) + settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier) runCurrent() - assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue() + assertThat(underTest.isEnabled(testUser1).first()).isTrue() - settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier) + settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier) runCurrent() - assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() + assertThat(underTest.isEnabled(testUser1).first()).isFalse() } @Test fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() = scope.runTest { - underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope) - settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier) - underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope) - settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_2.identifier) + underTest.isEnabled(testUser1).launchIn(backgroundScope) + settings.putIntForUser(SETTING_NAME, DISABLED, testUser1.identifier) + underTest.isEnabled(testUser2).launchIn(backgroundScope) + settings.putIntForUser(SETTING_NAME, DISABLED, testUser2.identifier) runCurrent() - assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse() - assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse() + assertThat(underTest.isEnabled(testUser1).first()).isFalse() + assertThat(underTest.isEnabled(testUser2).first()).isFalse() - settings.putIntForUser(SETTING_NAME, ENABLED, TEST_USER_1.identifier) + settings.putIntForUser(SETTING_NAME, ENABLED, testUser1.identifier) runCurrent() - assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue() - assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse() + assertThat(underTest.isEnabled(testUser1).first()).isTrue() + assertThat(underTest.isEnabled(testUser2).first()).isFalse() } @Test fun setEnabled() = scope.runTest { - val success = underTest.setIsEnabled(true, TEST_USER_1) + val success = underTest.setIsEnabled(true, testUser1) runCurrent() assertThat(success).isTrue() - val actualValue = settings.getIntForUser(SETTING_NAME, TEST_USER_1.identifier) + val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier) assertThat(actualValue).isEqualTo(ENABLED) } @Test fun setDisabled() = scope.runTest { - val success = underTest.setIsEnabled(false, TEST_USER_1) + val success = underTest.setIsEnabled(false, testUser1) runCurrent() assertThat(success).isTrue() - val actualValue = settings.getIntForUser(SETTING_NAME, TEST_USER_1.identifier) + val actualValue = settings.getIntForUser(SETTING_NAME, testUser1.identifier) assertThat(actualValue).isEqualTo(DISABLED) } @@ -134,7 +136,5 @@ class ColorInversionRepositoryImplTest : SysuiTestCase() { private const val SETTING_NAME = ACCESSIBILITY_DISPLAY_INVERSION_ENABLED private const val DISABLED = 0 private const val ENABLED = 1 - private val TEST_USER_1 = UserHandle.of(1)!! - private val TEST_USER_2 = UserHandle.of(2)!! } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java index 1c1335f0db4d..343280de17b8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -801,6 +801,20 @@ public class AuthControllerTest extends SysuiTestCase { } @Test + public void testOnBiometricPromptDismissedCallback_hideAuthenticationDialog() { + // GIVEN a callback is registered + AuthController.Callback callback = mock(AuthController.Callback.class); + mAuthController.addCallback(callback); + + // WHEN dialog is shown and then dismissed + showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); + mAuthController.hideAuthenticationDialog(mAuthController.mCurrentDialog.getRequestId()); + + // THEN callback should be received + verify(callback).onBiometricPromptDismissed(); + } + + @Test public void testSubscribesToLogContext() { mAuthController.setBiometricContextListener(mContextListener); verify(mLogContextInteractor).addBiometricContextListener(same(mContextListener)); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt index 15633d1baed1..4a39799fd64f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt @@ -18,6 +18,7 @@ package com.android.systemui.biometrics import android.hardware.biometrics.BiometricManager.Authenticators import android.hardware.biometrics.ComponentInfoInternal +import android.hardware.biometrics.PromptContentView import android.hardware.biometrics.PromptInfo import android.hardware.biometrics.SensorProperties import android.hardware.biometrics.SensorPropertiesInternal @@ -119,6 +120,7 @@ internal fun promptInfo( title: String = "title", subtitle: String = "sub", description: String = "desc", + contentView: PromptContentView? = null, credentialTitle: String? = "cred title", credentialSubtitle: String? = "cred sub", credentialDescription: String? = "cred desc", @@ -128,6 +130,7 @@ internal fun promptInfo( info.title = title info.subtitle = subtitle info.description = description + info.contentView = contentView credentialTitle?.let { info.deviceCredentialTitle = it } credentialSubtitle?.let { info.deviceCredentialSubtitle = it } credentialDescription?.let { info.deviceCredentialDescription = it } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index cec2d7459817..a59a4b864ac4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -1219,6 +1219,40 @@ public class UdfpsControllerTest extends SysuiTestCase { } @Test + public void onDownTouchReceivedWithoutPreviousUp() throws RemoteException { + final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L, + 0L); + final TouchProcessorResult processorResultDown = + new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN, + -1 /* pointerId */, touchData); + + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId, + BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + + verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture()); + + // WHEN ACTION_DOWN is received and touch is within sensor + when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn( + processorResultDown); + MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent); + mBiometricExecutor.runAllReady(); + firstDownEvent.recycle(); + + // And another ACTION_DOWN is received without an ACTION_UP before + MotionEvent secondDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0); + mTouchListenerCaptor.getValue().onTouch(mUdfpsView, secondDownEvent); + mBiometricExecutor.runAllReady(); + secondDownEvent.recycle(); + + // THEN the touch is still processed + verify(mFingerprintManager, times(2)).onPointerDown(anyLong(), anyInt(), anyInt(), + anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), + anyBoolean()); + } + + @Test public void onTouch_pilferPointerWhenAltBouncerShowing() throws RemoteException { final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt new file mode 100644 index 000000000000..ccf119ab3088 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorTest.kt @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2024 The Android Open 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.domain.interactor + +import android.hardware.biometrics.SensorLocationInternal +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.FingerprintSensorType +import com.android.systemui.biometrics.shared.model.SensorStrength +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class FingerprintPropertyInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val underTest = kosmos.fingerprintPropertyInteractor + private val repository = kosmos.fingerprintPropertyRepository + private val configurationRepository = kosmos.fakeConfigurationRepository + private val displayRepository = kosmos.displayRepository + + @Test + fun sensorLocation_resolution1f() = + testScope.runTest { + val currSensorLocation by collectLastValue(underTest.sensorLocation) + + displayRepository.emitDisplayChangeEvent(0) + runCurrent() + repository.setProperties( + sensorId = 0, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.UDFPS_OPTICAL, + sensorLocations = + mapOf( + Pair("", SensorLocationInternal("", 4, 4, 2)), + Pair("otherDisplay", SensorLocationInternal("", 1, 1, 1)) + ) + ) + runCurrent() + configurationRepository.setScaleForResolution(1f) + runCurrent() + + assertThat(currSensorLocation?.centerX).isEqualTo(4) + assertThat(currSensorLocation?.centerY).isEqualTo(4) + assertThat(currSensorLocation?.radius).isEqualTo(2) + } + + @Test + fun sensorLocation_resolution2f() = + testScope.runTest { + val currSensorLocation by collectLastValue(underTest.sensorLocation) + + displayRepository.emitDisplayChangeEvent(0) + runCurrent() + repository.setProperties( + sensorId = 0, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.UDFPS_OPTICAL, + sensorLocations = + mapOf( + Pair("", SensorLocationInternal("", 4, 4, 2)), + Pair("otherDisplay", SensorLocationInternal("", 1, 1, 1)) + ) + ) + runCurrent() + configurationRepository.setScaleForResolution(2f) + runCurrent() + + assertThat(currSensorLocation?.centerX).isEqualTo(4 * 2) + assertThat(currSensorLocation?.centerY).isEqualTo(4 * 2) + assertThat(currSensorLocation?.radius).isEqualTo(2 * 2) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt index ee46f76a94e4..63f6c2033ee1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt @@ -16,10 +16,10 @@ package com.android.systemui.bouncer.domain.interactor -import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.testing.TestableResources import android.view.View +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor @@ -60,7 +60,7 @@ import org.mockito.MockitoAnnotations @SmallTest @RunWithLooper(setAsMainLooper = true) -@RunWith(AndroidTestingRunner::class) +@RunWith(AndroidJUnit4::class) class PrimaryBouncerInteractorTest : SysuiTestCase() { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var repository: KeyguardBouncerRepository diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index 744b65f20592..cd83c07a3b38 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.shared.model.CommunalWidgetContentModel +import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState import com.android.systemui.communal.widgets.EditWidgetsActivityStarter import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -39,6 +40,9 @@ import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -69,9 +73,9 @@ class CommunalInteractorTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - testScope = TestScope() + testScope = TestScope(StandardTestDispatcher()) - val withDeps = CommunalInteractorFactory.create() + val withDeps = CommunalInteractorFactory.create(testScope) tutorialRepository = withDeps.tutorialRepository communalRepository = withDeps.communalRepository @@ -379,6 +383,131 @@ class CommunalInteractorTest : SysuiTestCase() { } @Test + fun transitionProgress_onTargetScene_fullProgress() = + testScope.runTest { + val targetScene = CommunalSceneKey.Blank + val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) + val transitionProgress by collectLastValue(transitionProgressFlow) + + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(targetScene) + ) + underTest.setTransitionState(transitionState) + + // We're on the target scene. + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene)) + } + + @Test + fun transitionProgress_notOnTargetScene_noProgress() = + testScope.runTest { + val targetScene = CommunalSceneKey.Blank + val currentScene = CommunalSceneKey.Communal + val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) + val transitionProgress by collectLastValue(transitionProgressFlow) + + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(currentScene) + ) + underTest.setTransitionState(transitionState) + + // Transition progress is still idle, but we're not on the target scene. + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(currentScene)) + } + + @Test + fun transitionProgress_transitioningToTrackedScene() = + testScope.runTest { + val currentScene = CommunalSceneKey.Communal + val targetScene = CommunalSceneKey.Blank + val transitionProgressFlow = underTest.transitionProgressToScene(targetScene) + val transitionProgress by collectLastValue(transitionProgressFlow) + + var transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(currentScene) + ) + underTest.setTransitionState(transitionState) + + // Progress starts at 0. + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(currentScene)) + + val progress = MutableStateFlow(0f) + transitionState = + MutableStateFlow( + ObservableCommunalTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + underTest.setTransitionState(transitionState) + + // Partially transition. + progress.value = .4f + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Transition(.4f)) + + // Transition is at full progress. + progress.value = 1f + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Transition(1f)) + + // Transition finishes. + transitionState = MutableStateFlow(ObservableCommunalTransitionState.Idle(targetScene)) + underTest.setTransitionState(transitionState) + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene)) + } + + @Test + fun transitionProgress_transitioningAwayFromTrackedScene() = + testScope.runTest { + val currentScene = CommunalSceneKey.Blank + val targetScene = CommunalSceneKey.Communal + val transitionProgressFlow = underTest.transitionProgressToScene(currentScene) + val transitionProgress by collectLastValue(transitionProgressFlow) + + var transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(currentScene) + ) + underTest.setTransitionState(transitionState) + + // Progress starts at 0. + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(currentScene)) + + val progress = MutableStateFlow(0f) + transitionState = + MutableStateFlow( + ObservableCommunalTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + underTest.setTransitionState(transitionState) + + // Partially transition. + progress.value = .4f + + // This is a transition we don't care about the progress of. + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.OtherTransition) + + // Transition is at full progress. + progress.value = 1f + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.OtherTransition) + + // Transition finishes. + transitionState = MutableStateFlow(ObservableCommunalTransitionState.Idle(targetScene)) + underTest.setTransitionState(transitionState) + assertThat(transitionProgress).isEqualTo(CommunalTransitionProgress.Idle(targetScene)) + } + + @Test fun isCommunalShowing() = testScope.runTest { var isCommunalShowing = collectLastValue(underTest.isCommunalShowing) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt new file mode 100644 index 000000000000..721fc4906aba --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/log/CommunalLoggerStartableTest.kt @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2024 The Android Open 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.communal.log + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.logging.UiEventLogger +import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory +import com.android.systemui.communal.shared.log.CommunalUiEvent +import com.android.systemui.communal.shared.model.CommunalSceneKey +import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +class CommunalLoggerStartableTest : SysuiTestCase() { + @Mock private lateinit var uiEventLogger: UiEventLogger + + private lateinit var testScope: TestScope + private lateinit var communalInteractor: CommunalInteractor + private lateinit var underTest: CommunalLoggerStartable + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + val withDeps = CommunalInteractorFactory.create() + testScope = withDeps.testScope + communalInteractor = withDeps.communalInteractor + + underTest = + CommunalLoggerStartable( + testScope.backgroundScope, + communalInteractor, + uiEventLogger, + ) + underTest.start() + } + + @Test + fun transitionStateLogging_enterCommunalHub() = + testScope.runTest { + // Transition state is default (non-communal) + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.DEFAULT)) + communalInteractor.setTransitionState(transitionState) + runCurrent() + + // Verify nothing is logged from the default state + verify(uiEventLogger, never()).log(any()) + + // Start transition to communal + transitionState.value = transition(to = CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START) + + // Finish transition to communal + transitionState.value = idle(CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_FINISH) + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN) + } + + @Test + fun transitionStateLogging_enterCommunalHub_canceled() = + testScope.runTest { + // Transition state is default (non-communal) + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.DEFAULT)) + communalInteractor.setTransitionState(transitionState) + runCurrent() + + // Verify nothing is logged from the default state + verify(uiEventLogger, never()).log(any()) + + // Start transition to communal + transitionState.value = transition(to = CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START) + + // Cancel the transition + transitionState.value = idle(CommunalSceneKey.DEFAULT) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_CANCEL) + + // Verify neither SHOWN nor GONE is logged + verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN) + verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE) + } + + @Test + fun transitionStateLogging_exitCommunalHub() = + testScope.runTest { + // Transition state is communal + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.Communal)) + communalInteractor.setTransitionState(transitionState) + runCurrent() + + // Verify SHOWN is logged when it's the default state + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN) + + // Start transition from communal + transitionState.value = transition(from = CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START) + + // Finish transition to communal + transitionState.value = idle(CommunalSceneKey.DEFAULT) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_FINISH) + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_GONE) + } + + @Test + fun transitionStateLogging_exitCommunalHub_canceled() = + testScope.runTest { + // Transition state is communal + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>(idle(CommunalSceneKey.Communal)) + communalInteractor.setTransitionState(transitionState) + runCurrent() + + // Clear the initial SHOWN event from the logger + clearInvocations(uiEventLogger) + + // Start transition from communal + transitionState.value = transition(from = CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START) + + // Cancel the transition + transitionState.value = idle(CommunalSceneKey.Communal) + runCurrent() + + // Verify UiEvent logged + verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_CANCEL) + + // Verify neither SHOWN nor GONE is logged + verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_SHOWN) + verify(uiEventLogger, never()).log(CommunalUiEvent.COMMUNAL_HUB_GONE) + } + + private fun transition( + from: CommunalSceneKey = CommunalSceneKey.DEFAULT, + to: CommunalSceneKey = CommunalSceneKey.DEFAULT, + ): ObservableCommunalTransitionState.Transition { + return ObservableCommunalTransitionState.Transition( + fromScene = from, + toScene = to, + progress = emptyFlow(), + isInitiatedByUserInput = true, + isUserInputOngoing = emptyFlow(), + ) + } + + private fun idle(sceneKey: CommunalSceneKey): ObservableCommunalTransitionState.Idle { + return ObservableCommunalTransitionState.Idle(sceneKey) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index ff6fd43745df..54510a82201a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -21,7 +21,6 @@ import android.app.Activity.RESULT_OK import android.app.smartspace.SmartspaceTarget import android.appwidget.AppWidgetHost import android.content.ComponentName -import android.os.PowerManager import android.provider.Settings import android.widget.RemoteViews import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -41,13 +40,11 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.ui.MediaHost -import com.android.systemui.shade.ShadeViewController import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import javax.inject.Provider import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -64,8 +61,6 @@ import org.mockito.MockitoAnnotations @RunWith(AndroidJUnit4::class) class CommunalEditModeViewModelTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost - @Mock private lateinit var shadeViewController: ShadeViewController - @Mock private lateinit var powerManager: PowerManager @Mock private lateinit var appWidgetHost: AppWidgetHost @Mock private lateinit var uiEventLogger: UiEventLogger @@ -97,8 +92,6 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { CommunalEditModeViewModel( withDeps.communalInteractor, appWidgetHost, - Provider { shadeViewController }, - powerManager, mediaHost, uiEventLogger, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 16e0bc00ad35..804c0528c46c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.communal.view.viewmodel import android.app.smartspace.SmartspaceTarget -import android.os.PowerManager import android.provider.Settings import android.widget.RemoteViews import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -31,31 +30,33 @@ import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalWidgetContentModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel +import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS import com.android.systemui.communal.widgets.WidgetInteractionHandler import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.media.controls.ui.MediaHierarchyManager import com.android.systemui.media.controls.ui.MediaHost -import com.android.systemui.shade.ShadeViewController import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat -import javax.inject.Provider +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations +@OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class CommunalViewModelTest : SysuiTestCase() { @Mock private lateinit var mediaHost: MediaHost - @Mock private lateinit var shadeViewController: ShadeViewController - @Mock private lateinit var powerManager: PowerManager private lateinit var testScope: TestScope @@ -84,16 +85,22 @@ class CommunalViewModelTest : SysuiTestCase() { underTest = CommunalViewModel( + testScope, withDeps.communalInteractor, WidgetInteractionHandler(mock()), withDeps.tutorialInteractor, - Provider { shadeViewController }, - powerManager, mediaHost, ) } @Test + fun init_initsMediaHost() = + testScope.runTest { + // MediaHost is initialized as soon as the class is created. + verify(mediaHost).init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB) + } + + @Test fun tutorial_tutorialNotCompletedAndKeyguardVisible_showTutorialContent() = testScope.runTest { // Keyguard showing, and tutorial not started. @@ -159,4 +166,44 @@ class CommunalViewModelTest : SysuiTestCase() { assertThat(communalContent?.get(4)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } + + @Test + fun dismissCta_hidesCtaTileAndShowsPopup_thenHidesPopupAfterTimeout() = + testScope.runTest { + tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) + communalRepository.setCtaTileInViewModeVisibility(true) + + val communalContent by collectLastValue(underTest.communalContent) + val isPopupOnDismissCtaShowing by collectLastValue(underTest.isPopupOnDismissCtaShowing) + + assertThat(communalContent?.size).isEqualTo(1) + assertThat(communalContent?.get(0)) + .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) + + underTest.onDismissCtaTile() + + // hide CTA tile and show the popup + assertThat(communalContent).isEmpty() + assertThat(isPopupOnDismissCtaShowing).isEqualTo(true) + + // hide popup after time elapsed + advanceTimeBy(POPUP_AUTO_HIDE_TIMEOUT_MS) + assertThat(isPopupOnDismissCtaShowing).isEqualTo(false) + } + + @Test + fun popup_onDismiss_hidesImmediately() = + testScope.runTest { + tutorialRepository.setTutorialSettingState(Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED) + communalRepository.setCtaTileInViewModeVisibility(true) + + val isPopupOnDismissCtaShowing by collectLastValue(underTest.isPopupOnDismissCtaShowing) + + underTest.onDismissCtaTile() + assertThat(isPopupOnDismissCtaShowing).isEqualTo(true) + + // dismiss the popup directly + underTest.onHidePopupAfterDismissCta() + assertThat(isPopupOnDismissCtaShowing).isEqualTo(false) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java index 3d1efa59a11b..5827671e22b8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandlerTest.java @@ -293,8 +293,8 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { } /** - * Verifies that swiping up when the lock pattern is not secure does not consume the scroll - * gesture or expand. + * Verifies that swiping up when the lock pattern is not secure dismissed dream and consumes + * the gesture. */ @Test public void testSwipeUp_keyguardNotSecure_doesNotExpand() { @@ -314,11 +314,44 @@ public class BouncerSwipeTouchHandlerTest extends SysuiTestCase { reset(mScrimController); + // Scroll gesture is consumed. + assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) + .isTrue(); + // We should not expand since the keyguard is not secure + verify(mScrimController, never()).expand(any()); + // Since we are swiping up, we should wake from dreams. + verify(mCentralSurfaces).awakenDreams(); + } + + /** + * Verifies that swiping down when the lock pattern is not secure does not dismiss the dream. + */ + @Test + public void testSwipeDown_keyguardNotSecure_doesNotExpand() { + when(mLockPatternUtils.isSecure(CURRENT_USER_INFO.id)).thenReturn(false); + mTouchHandler.onSessionStart(mTouchSession); + ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = + ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); + verify(mTouchSession).registerGestureListener(gestureListenerCaptor.capture()); + + final OnGestureListener gestureListener = gestureListenerCaptor.getValue(); + + final float distanceY = SCREEN_HEIGHT_PX * 0.3f; + // Swiping down near the bottom of the screen where the touch initiation region is. + final MotionEvent event1 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX - distanceY, 0); + final MotionEvent event2 = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, + 0, SCREEN_HEIGHT_PX, 0); + + reset(mScrimController); + // Scroll gesture is not consumed. assertThat(gestureListener.onScroll(event1, event2, 0, distanceY)) - .isFalse(); + .isTrue(); // We should not expand since the keyguard is not secure verify(mScrimController, never()).expand(any()); + // Since we are swiping down, we should not dismiss the dream. + verify(mCentralSurfaces, never()).awakenDreams(); } private void verifyScroll(float percent, Direction direction, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt index b483085cf1e5..9bccf4e26e87 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt @@ -82,6 +82,7 @@ class LightRevealScrimInteractorTest : SysuiTestCase() { keyguardTransitionInteractor, fakeLightRevealScrimRepository, testScope.backgroundScope, + mock(), mock() ) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt index e7037a682cca..9daf1860ebb8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt @@ -94,7 +94,7 @@ class AlternateBouncerToAodTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(6) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt new file mode 100644 index 000000000000..c7ab52974852 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.Flags +import com.android.systemui.flags.fakeFeatureFlagsClassic +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class AlternateBouncerToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { + private val kosmos = + testKosmos().apply { + fakeFeatureFlagsClassic.apply { + set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false) + set(Flags.FULL_SCREEN_USER_SWITCHER, false) + } + } + private val testScope = kosmos.testScope + private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + private val underTest = kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel + + @Test + fun deviceEntryParentViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.PRIMARY_BOUNCER, + value = value, + transitionState = state, + ownerName = "AlternateBouncerToPrimaryBouncerTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt index e141c2b3107f..f1690dafe75a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelTest.kt @@ -95,7 +95,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(6) + assertThat(values.size).isEqualTo(7) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } } @@ -117,7 +117,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(3) + assertThat(values.size).isEqualTo(4) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -232,7 +232,7 @@ class DreamingToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt index 897ce6d305b6..f763a6790b51 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelTest.kt @@ -59,9 +59,9 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { testScope, ) - // Only three values should be present, since the dream overlay runs for a small + // Only five values should be present, since the dream overlay runs for a small // fraction of the overall animation time - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -84,7 +84,7 @@ class GoneToDreamingTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt index 5b88ebe69bfe..fd2fd2f04cde 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt @@ -203,4 +203,38 @@ class KeyguardRootViewModelTest : SysuiTestCase() { assertThat(isVisible?.isAnimating).isEqualTo(false) } + + @Test + fun alpha_glanceableHubOpen_isZero() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha) + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GLANCEABLE_HUB, + testScope, + ) + + assertThat(alpha).isEqualTo(0f) + } + + @Test + fun alpha_glanceableHubClosed_isOne() = + testScope.runTest { + val alpha by collectLastValue(underTest.alpha) + + // Transition to the glanceable hub and back. + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GLANCEABLE_HUB, + testScope, + ) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.LOCKSCREEN, + testScope, + ) + + assertThat(alpha).isEqualTo(1.0f) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt index 4843f8ba4249..74025fd6e100 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt @@ -73,9 +73,9 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { testScope = testScope, ) - // Only three values should be present, since the dream overlay runs for a small + // Only five values should be present, since the dream overlay runs for a small // fraction of the overall animation time - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } @@ -98,10 +98,10 @@ class LockscreenToDreamingTransitionViewModelTest : SysuiTestCase() { testScope = testScope, ) - assertThat(values.size).isEqualTo(5) + assertThat(values.size).isEqualTo(6) values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) } // Validate finished value - assertThat(values[4]).isEqualTo(0f) + assertThat(values[5]).isEqualTo(0f) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt index a1b8aab402a7..6fcb0c11edad 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt @@ -74,9 +74,9 @@ class LockscreenToOccludedTransitionViewModelTest : SysuiTestCase() { ), testScope = testScope, ) - // Only 3 values should be present, since the dream overlay runs for a small fraction + // Only 5 values should be present, since the dream overlay runs for a small fraction // of the overall animation time - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index 2111ad5d975e..639114c15000 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -54,6 +55,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { fun lockscreenFadeIn() = testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionSteps( listOf( @@ -83,6 +85,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { 100 ) val values by collectValues(underTest.lockscreenTranslationY) + runCurrent() keyguardTransitionRepository.sendTransitionSteps( listOf( @@ -95,7 +98,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(4) + assertThat(values.size).isEqualTo(5) values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } } @@ -107,6 +110,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { 100 ) val values by collectValues(underTest.lockscreenTranslationY) + runCurrent() keyguardTransitionRepository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) @@ -117,6 +121,7 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { fun deviceEntryParentViewFadeIn() = testScope.runTest { val values by collectValues(underTest.deviceEntryParentViewAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionSteps( listOf( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index 90b83620084c..30b87bbbcf11 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.testKosmos import com.android.systemui.util.mockito.whenever import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -65,6 +66,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { fun bouncerAlpha() = testScope.runTest { val values by collectValues(underTest.bouncerAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionSteps( listOf( @@ -83,6 +85,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { fun bouncerAlpha_runDimissFromKeyguard() = testScope.runTest { val values by collectValues(underTest.bouncerAlpha) + runCurrent() whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) @@ -95,7 +98,7 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { testScope, ) - assertThat(values.size).isEqualTo(1) + assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(0f) } } @@ -103,11 +106,12 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { fun lockscreenAlpha() = testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(1) + assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(0f) } } @@ -115,13 +119,14 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { fun lockscreenAlpha_runDimissFromKeyguard() = testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) + runCurrent() sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(1) + assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(1f) } } @@ -129,13 +134,14 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { fun lockscreenAlpha_leaveShadeOpen() = testScope.runTest { val values by collectValues(underTest.lockscreenAlpha) + runCurrent() sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) keyguardTransitionRepository.sendTransitionStep(step(1f)) - assertThat(values.size).isEqualTo(1) + assertThat(values.size).isEqualTo(2) values.forEach { assertThat(it).isEqualTo(1f) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt index bd1c310ab8de..c1049773cabf 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt @@ -16,32 +16,45 @@ package com.android.systemui.qs.tiles.base.actions +import android.app.PendingIntent +import android.content.ComponentName import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.content.pm.PackageManager.ResolveInfoFlags +import android.content.pm.ResolveInfo +import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.util.mockito.argThat +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatcher import org.mockito.Mock import org.mockito.Mockito.any import org.mockito.Mockito.eq +import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidJUnit4::class) class QSTileIntentUserInputHandlerTest : SysuiTestCase() { - - @Mock private lateinit var activityStarted: ActivityStarter + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var activityStarter: ActivityStarter lateinit var underTest: QSTileIntentUserInputHandler @Before fun setup() { MockitoAnnotations.initMocks(this) - underTest = QSTileIntentUserInputHandlerImpl(activityStarted) + underTest = QSTileIntentUserInputHandlerImpl(activityStarter, packageManager, user) } @Test @@ -50,6 +63,103 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() { underTest.handle(null, intent) - verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) + verify(activityStarter).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) + } + + @Test + fun testPassesActivityPendingIntentToStarterAsPendingIntent() { + val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } + + underTest.handle(null, pendingIntent, true) + + verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) + } + + @Test + fun testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStart() { + val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } + + underTest.handle(null, pendingIntent, false) + + verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) + } + + @Test + fun testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStarts() { + val pendingIntent = + mock<PendingIntent> { + whenever(isActivity).thenReturn(false) + whenever(creatorPackage).thenReturn(ORIGINAL_PACKAGE) + } + setUpQueryResult(listOf(createActivityInfo(testResolvedComponent, exported = true))) + + underTest.handle(null, pendingIntent, true) + + val expectedIntent = + Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setPackage(null) + .addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + ) + .setComponent(testResolvedComponent) + + verify(activityStarter) + .postStartActivityDismissingKeyguard( + argThat(IntentMatcher(expectedIntent)), + eq(0), + any() + ) + } + + @Test + fun testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivity() { + val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) } + + underTest.handle(null, pendingIntent, false) + + verify(activityStarter, never()) + .postStartActivityDismissingKeyguard(any(Intent::class.java), eq(0), any()) + } + + private fun createActivityInfo( + componentName: ComponentName, + exported: Boolean = false, + ): ActivityInfo { + return ActivityInfo().apply { + packageName = componentName.packageName + name = componentName.className + this.exported = exported + } + } + + private fun setUpQueryResult(infos: List<ActivityInfo>) { + `when`( + packageManager.queryIntentActivitiesAsUser( + any(Intent::class.java), + any(ResolveInfoFlags::class.java), + eq(user.identifier) + ) + ) + .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } }) + } + + private class IntentMatcher(intent: Intent) : ArgumentMatcher<Intent> { + private val expectedIntent = intent + override fun matches(argument: Intent?): Boolean { + return argument?.action.equals(expectedIntent.action) && + argument?.`package`.equals(expectedIntent.`package`) && + argument?.component?.equals(expectedIntent.component)!! && + argument?.categories?.equals(expectedIntent.categories)!! && + argument?.flags?.equals(expectedIntent.flags)!! + } + } + + companion object { + private const val ORIGINAL_PACKAGE = "original_pkg" + private const val TEST_PACKAGE = "test_pkg" + private const val TEST_COMPONENT_CLASS_NAME = "test_component_class_name" + private val testResolvedComponent = ComponentName(TEST_PACKAGE, TEST_COMPONENT_CLASS_NAME) + private val user = UserHandle.of(0) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt index e44c8493244c..be2da174250b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt @@ -18,42 +18,25 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.app.AlarmManager.AlarmClockInfo import android.app.PendingIntent -import android.content.Intent import android.provider.AlarmClock import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler +import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel -import com.android.systemui.util.mockito.capture -import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.nullable import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.Mockito.verify @SmallTest @RunWith(AndroidJUnit4::class) class AlarmTileUserActionInteractorTest : SysuiTestCase() { - private lateinit var activityStarter: ActivityStarter - private lateinit var intentCaptor: ArgumentCaptor<Intent> - private lateinit var pendingIntentCaptor: ArgumentCaptor<PendingIntent> - - lateinit var underTest: AlarmTileUserActionInteractor - - @Before - fun setup() { - activityStarter = mock<ActivityStarter>() - intentCaptor = ArgumentCaptor.forClass(Intent::class.java) - pendingIntentCaptor = ArgumentCaptor.forClass(PendingIntent::class.java) - underTest = AlarmTileUserActionInteractor(activityStarter) - } + private val inputHandler = FakeQSTileIntentUserInputHandler() + private val underTest = AlarmTileUserActionInteractor(inputHandler) @Test fun handleClickWithDefaultIntent() = runTest { @@ -62,21 +45,21 @@ class AlarmTileUserActionInteractorTest : SysuiTestCase() { underTest.handleInput(click(inputModel)) - verify(activityStarter) - .postStartActivityDismissingKeyguard(capture(intentCaptor), eq(0), nullable()) - assertThat(intentCaptor.value.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) + QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { + assertThat(it.intent.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS) + } } @Test fun handleClickWithPendingIntent() = runTest { - val expectedIntent: PendingIntent = mock<PendingIntent>() + val expectedIntent = mock<PendingIntent>() val alarmInfo = AlarmClockInfo(1L, expectedIntent) val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo) underTest.handleInput(click(inputModel)) - verify(activityStarter) - .postStartActivityDismissingKeyguard(capture(pendingIntentCaptor), nullable()) - assertThat(pendingIntentCaptor.value).isEqualTo(expectedIntent) + QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOnePendingIntentInput { + assertThat(it.pendingIntent).isEqualTo(expectedIntent) + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java index 01fe40f6dff6..d0e05fa60114 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java @@ -42,19 +42,15 @@ import android.content.Intent; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.net.Uri; -import android.os.Handler; -import android.os.Looper; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.util.SparseArray; +import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; @@ -86,8 +82,7 @@ import java.util.Collection; import java.util.concurrent.Executor; @SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@RunWith(AndroidJUnit4.class) public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCase { @Mock private NotificationPresenter mPresenter; @@ -128,6 +123,7 @@ public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCa private NotificationEntry mSecondaryUserNotif; private NotificationEntry mWorkProfileNotif; private final FakeFeatureFlagsClassic mFakeFeatureFlags = new FakeFeatureFlagsClassic(); + private Executor mMainExecutor = Runnable::run; // Direct executor private Executor mBackgroundExecutor = Runnable::run; // Direct executor @Before @@ -156,8 +152,6 @@ public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCa mSecondaryUser)); when(mUserManager.getProfilesIncludingCommunal(mSecondaryUser.id)).thenReturn( Lists.newArrayList(mSecondaryUser, mCommunalUser)); - mDependency.injectTestDependency(Dependency.MAIN_HANDLER, - Handler.createAsync(Looper.myLooper())); Notification notifWithPrivateVisibility = new Notification(); notifWithPrivateVisibility.visibility = Notification.VISIBILITY_PRIVATE; @@ -378,28 +372,24 @@ public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCa // first call explicitly sets user 0 to not public; notifies mLockscreenUserManager.updatePublicMode(); - TestableLooper.get(this).processAllMessages(); assertFalse(mLockscreenUserManager.isLockscreenPublicMode(0)); verify(listener).onNotificationStateChanged(); clearInvocations(listener); // calling again has no changes; does not notify mLockscreenUserManager.updatePublicMode(); - TestableLooper.get(this).processAllMessages(); assertFalse(mLockscreenUserManager.isLockscreenPublicMode(0)); verify(listener, never()).onNotificationStateChanged(); // Calling again with keyguard now showing makes user 0 public; notifies when(mKeyguardStateController.isShowing()).thenReturn(true); mLockscreenUserManager.updatePublicMode(); - TestableLooper.get(this).processAllMessages(); assertTrue(mLockscreenUserManager.isLockscreenPublicMode(0)); verify(listener).onNotificationStateChanged(); clearInvocations(listener); // calling again has no changes; does not notify mLockscreenUserManager.updatePublicMode(); - TestableLooper.get(this).processAllMessages(); assertTrue(mLockscreenUserManager.isLockscreenPublicMode(0)); verify(listener, never()).onNotificationStateChanged(); } @@ -595,8 +585,7 @@ public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCa (() -> mOverviewProxyService), NotificationLockscreenUserManagerMainThreadTest.this.mKeyguardManager, mStatusBarStateController, - Handler.createAsync(Looper.myLooper()), - Handler.createAsync(Looper.myLooper()), + mMainExecutor, mBackgroundExecutor, mDeviceProvisionedController, mKeyguardStateController, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index 757f16cac227..bcc0710359cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -29,10 +29,11 @@ import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; import static android.os.UserHandle.USER_ALL; import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; -import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -62,13 +63,11 @@ import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.FlagsParameterization; import android.provider.Settings; -import android.testing.TestableLooper; import android.util.SparseArray; import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; -import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; @@ -88,6 +87,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.time.FakeSystemClock; + import com.google.android.collect.Lists; import org.junit.After; @@ -109,7 +109,6 @@ import platform.test.runner.parameterized.Parameters; @SmallTest @RunWith(ParameterizedAndroidJunit4.class) -@TestableLooper.RunWithLooper public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Parameters(name = "{0}") @@ -197,8 +196,6 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { mSecondaryUser)); when(mUserManager.getProfilesIncludingCommunal(mSecondaryUser.id)).thenReturn( Lists.newArrayList(mSecondaryUser, mCommunalUser)); - mDependency.injectTestDependency(Dependency.MAIN_HANDLER, - mockExecutorHandler(mMainExecutor)); Notification notifWithPrivateVisibility = new Notification(); notifWithPrivateVisibility.visibility = VISIBILITY_PRIVATE; @@ -949,8 +946,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { (() -> mOverviewProxyService), NotificationLockscreenUserManagerTest.this.mKeyguardManager, mStatusBarStateController, - mockExecutorHandler(mMainExecutor), - mockExecutorHandler(mBackgroundExecutor), + mMainExecutor, mBackgroundExecutor, mDeviceProvisionedController, mKeyguardStateController, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt new file mode 100644 index 000000000000..8a0400d092c3 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2023 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.data.repository + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.statusbar.NotificationRemoteInputManager +import com.android.systemui.util.mockito.withArgCaptor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidJUnit4::class) +class RemoteInputRepositoryImplTest : SysuiTestCase() { + @Mock private lateinit var remoteInputManager: NotificationRemoteInputManager + + private lateinit var testScope: TestScope + private lateinit var underTest: RemoteInputRepositoryImpl + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + testScope = TestScope() + underTest = RemoteInputRepositoryImpl(remoteInputManager) + } + + @Test + fun isRemoteInputActive_updatesOnChange() = + testScope.runTest { + val active by collectLastValue(underTest.isRemoteInputActive) + runCurrent() + assertThat(active).isFalse() + + val callback = withArgCaptor { + verify(remoteInputManager).addControllerCallback(capture()) + } + + callback.onRemoteInputActive(true) + runCurrent() + assertThat(active).isTrue() + + callback.onRemoteInputActive(false) + runCurrent() + assertThat(active).isFalse() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt new file mode 100644 index 000000000000..12469ddcafc2 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.data.repository.fakeRemoteInputRepository +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class RemoteInputInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val fakeRemoteInputRepository = kosmos.fakeRemoteInputRepository + private val underTest = kosmos.remoteInputInteractor + + @Test + fun isRemoteInputActive_true() = + testScope.runTest { + val active by collectLastValue(underTest.isRemoteInputActive) + + fakeRemoteInputRepository.isRemoteInputActive.value = true + runCurrent() + + assertThat(active).isTrue() + } + + @Test + fun isRemoteInputActive_false() = + testScope.runTest { + val active by collectLastValue(underTest.isRemoteInputActive) + + fakeRemoteInputRepository.isRemoteInputActive.value = false + runCurrent() + + assertThat(active).isFalse() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt new file mode 100644 index 000000000000..ebc81be6d4b6 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.statusbar.policy.data.repository + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.policy.DeviceProvisionedController +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener +import com.android.systemui.statusbar.policy.deviceProvisionedController +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.argumentCaptor +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +class UserSetupRepositoryTest : SysuiTestCase() { + + private val kosmos = testKosmos() + + private val testScope = kosmos.testScope + private val deviceProvisionedController : DeviceProvisionedController = mock() + + private val underTest = UserSetupRepositoryImpl( + deviceProvisionedController, + kosmos.testDispatcher, + kosmos.applicationCoroutineScope, + ) + + @Test + fun userSetup_defaultFalse() = + testScope.runTest { + val latest by collectLastValue(underTest.isUserSetUp) + + assertThat(latest).isFalse() + } + + @Test + fun userSetup_updatesOnChange() = + testScope.runTest { + val latest by collectLastValue(underTest.isUserSetUp) + runCurrent() + + whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true) + val callback = getDeviceProvisionedListener() + callback.onUserSetupChanged() + + assertThat(latest).isTrue() + } + + private fun getDeviceProvisionedListener(): DeviceProvisionedListener { + val captor = argumentCaptor<DeviceProvisionedListener>() + verify(deviceProvisionedController).addCallback(captor.capture()) + return captor.value!! + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt new file mode 100644 index 000000000000..26c0f80c53de --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy.domain.interactor + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class UserSetupInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val fakeUserSetupRepository = kosmos.fakeUserSetupRepository + private val underTest = kosmos.userSetupInteractor + + @Test + fun isUserSetup_false() = + testScope.runTest { + val setup by collectLastValue(underTest.isUserSetUp) + + fakeUserSetupRepository.setUserSetUp(false) + + assertThat(setup).isFalse() + } + + @Test + fun isUserSetup_true() = + testScope.runTest { + val setup by collectLastValue(underTest.isUserSetUp) + + fakeUserSetupRepository.setUserSetUp(true) + + assertThat(setup).isTrue() + } +} diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java index 3e5e8a0d462e..f0ce4604309d 100644 --- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java +++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/PluginLifecycleManager.java @@ -18,6 +18,8 @@ package com.android.systemui.plugins; import android.content.ComponentName; +import java.util.function.BiConsumer; + /** * Provides the ability for consumers to control plugin lifecycle. * @@ -33,11 +35,8 @@ public interface PluginLifecycleManager<T extends Plugin> { /** Returns the currently loaded plugin instance (if plugin is loaded) */ T getPlugin(); - /** Returns true if the lifecycle manager should log debug messages */ - boolean getIsDebug(); - - /** Sets whether or not hte lifecycle manager should log debug messages */ - void setIsDebug(boolean debug); + /** Log tag and messages will be sent to the provided Consumer */ + void setLogFunc(BiConsumer<String, String> logConsumer); /** returns true if the plugin is currently loaded */ default boolean isLoaded() { diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index 18d63ab35e94..01b99ec5700e 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -104,7 +104,7 @@ <string name="kg_password_pin_failed" msgid="5136259126330604009">"SIM पिन की कार्यवाही विफल रही!"</string> <string name="kg_password_puk_failed" msgid="6778867411556937118">"SIM PUK की कार्यवाही विफल रही!"</string> <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"इनपुट का तरीका बदलें"</string> - <string name="airplane_mode" msgid="2528005343938497866">"हवाई जहाज़ मोड"</string> + <string name="airplane_mode" msgid="2528005343938497866">"फ़्लाइट मोड"</string> <string name="kg_prompt_reason_restart_pattern" msgid="3321211830602827742">"डिवाइस रीस्टार्ट करने पर, पैटर्न ड्रॉ करना ज़रूरी है"</string> <string name="kg_prompt_reason_restart_pin" msgid="2672166323886110512">"डिवाइस रीस्टार्ट करने पर, पिन डालना ज़रूरी है"</string> <string name="kg_prompt_reason_restart_password" msgid="3967993994418885887">"डिवाइस रीस्टार्ट करने पर, पासवर्ड डालना ज़रूरी है"</string> diff --git a/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml b/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml new file mode 100644 index 000000000000..2161a62ada9c --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_no_internet_branded_vpn.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2023, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="17dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h4V9H12.09zM18,13hv3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H18V13z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,10h-2v8h2V10z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,20h-2v2h2V20z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml b/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml new file mode 100644 index 000000000000..2161a62ada9c --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_no_internet_vpn_ic.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 2023, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="17dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M12.09,9C11.11,7.5 9.43,6.5 7.5,6.5C4.46,6.5 2,8.96 2,12c0,3.04 2.46,5.5 5.5,5.5c1.93,0 3.61,-1 4.59,-2.5H14v3h4V9H12.09zM18,13hv3h-2v-3h-5.16c-0.43,1.44 -1.76,2.5 -3.34,2.5C5.57,15.5 4,13.93 4,12c0,-1.93 1.57,-3.5 3.5,-3.5c1.58,0 2.9,1.06 3.34,2.5H18V13z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M7.5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,10h-2v8h2V10z"/> + <path + android:fillColor="#FFFFFFFF" + android:pathData="M22,20h-2v2h2V20z"/> +</vector> diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml new file mode 100644 index 000000000000..390875702cfe --- /dev/null +++ b/packages/SystemUI/res/layout/biometric_prompt_content_layout.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/customized_view" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_vertical" + android:orientation="vertical" + style="@style/AuthCredentialContentLayoutStyle"> + + <TextView + android:id="@+id/customized_view_title" + style="@style/TextAppearance.AuthCredential.ContentViewTitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="marquee" + android:marqueeRepeatLimit="1" + android:singleLine="true" /> +</LinearLayout> diff --git a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml b/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml index 9d16f32db932..e39f60f349bc 100644 --- a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml @@ -1,6 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> - -<!-- +<?xml version="1.0" encoding="utf-8"?><!-- ~ Copyright (C) 2023 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,10 +14,8 @@ ~ limitations under the License. --> -<!-- Copied from //frameworks/base/core/res/res/drawable/item_background_material.xml --> -<ripple xmlns:android="http://schemas.android.com/apk/res/android" - android:color="@color/autofill_light_colorControlHighlight"> - <item android:id="@android:id/mask"> - <color android:color="@android:color/white"/> - </item> -</ripple>
\ No newline at end of file +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + style="@style/TextAppearance.AuthCredential.ContentViewListItem" + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1.0" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml new file mode 100644 index 000000000000..6c867365e92c --- /dev/null +++ b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2023 The Android Open 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="@dimen/biometric_prompt_content_list_row_height" + android:gravity="center_vertical|start" + android:orientation="horizontal" /> diff --git a/packages/SystemUI/res/layout/biometric_prompt_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_layout.xml index bea0e13c77dc..23fbb12f3036 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_layout.xml @@ -48,6 +48,23 @@ android:importantForAccessibility="no" style="@style/TextAppearance.AuthCredential.Description"/> + <Space + android:id="@+id/space_above_content" + android:layout_width="match_parent" + android:layout_height="@dimen/biometric_prompt_space_above_content" + android:visibility="gone" /> + + <ScrollView + android:id="@+id/customized_view_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:fadeScrollbars="false" + android:gravity="center_vertical" + android:orientation="vertical" + android:paddingHorizontal="@dimen/biometric_prompt_content_container_padding_horizontal" + android:scrollbars="vertical" + android:visibility="gone" /> + <Space android:id="@+id/space_above_icon" android:layout_width="match_parent" android:layout_height="48dp" /> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 6d7ce0623817..e602d6c8848d 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -107,4 +107,13 @@ <include layout="@layout/ambient_indication" android:id="@id/ambient_indication_container" /> + + <FrameLayout + android:id="@+id/smartspace_container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_marginBottom="@dimen/ambient_indication_margin_bottom" + android:visibility="gone"> + </FrameLayout> </com.android.systemui.statusbar.phone.KeyguardBottomAreaView> diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index fc0bf242dc1e..4cb7591a3502 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -23,7 +23,6 @@ android:layout_width="match_parent" android:layout_height="@dimen/status_bar_header_height_keyguard" android:baselineAligned="false" - android:gravity="center_vertical" > <LinearLayout diff --git a/packages/SystemUI/res/layout/power_notification_controls_settings.xml b/packages/SystemUI/res/layout/power_notification_controls_settings.xml deleted file mode 100644 index 83c8a51f6330..000000000000 --- a/packages/SystemUI/res/layout/power_notification_controls_settings.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - - <include layout="@layout/switch_bar" /> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="16dp" - android:text="@string/power_notification_controls_description"/> - -</LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index db4cca3087bc..aeb831114f07 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Kon nie Gesigslot opstel nie. Gaan na Instellings toe om weer te probeer."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak die vingerafdruksensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Druk die ontsluitikoon om voort te gaan"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kan nie gesig herken nie. Gebruik eerder vingerafdruk."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Kan nie gesig herken nie"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gebruik eerder vingerafdruk"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Gesigslot is onbeskikbaar"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth gekoppel."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laai tans • Vol oor <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swiep links om die gemeenskaplike tutoriaal te begin"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Maak die legstukredigeerder oop"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Opstelling"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Berging"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Wenke"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Kitsprogramme"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> loop tans"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Program is oopgemaak sonder dat dit geïnstalleer is."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik om toeganklikheidkenmerke oop te maak Pasmaak of vervang knoppie in Instellings.\n\n"<annotation id="link">"Bekyk instellings"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Skuif knoppie na kant om dit tydelik te versteek"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Ontdoen"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>-kortpad is verwyder"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# kortpad is verwyder}other{# kortpaaie is verwyder}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Beweeg na links bo"</string> @@ -1207,9 +1225,9 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikerteenwoordigheid is bespeur"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string> <string name="install_app" msgid="5066668100199613936">"Installeer app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swiep om voort te gaan"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> - <skip /> + <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jou binneste skerm sal weerspieël word. Jou boonste skerm sal afgeskakel word."</string> <string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Maak toe"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Skerm is gekoppel"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 40fddc8b97f7..8bad367f11b0 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"በመልክ መክፈትን ማዋቀር አልተቻለም። እንደገና ለመሞከር ወደ ቅንብሮች ይሂዱ።"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"የጣት አሻራ ዳሳሹን ይንኩ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ለመቀጠል የክፈት አዶውን ይጫኑ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"መልክን መለየት አልተቻለም። በምትኩ የጣት አሻራ ይጠቀሙ።"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"መልክን መለየት አልተቻለም"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"በምትኩ የጣት አሻራን ይጠቀሙ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"በመልክ መክፈት አይገኝም"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ብሉቱዝ ተያይዟል።"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ኃይል በመሙላት ላይ • በ<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ውስጥ ይሞላል"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"የጋራ አጋዥ ሥልጠናውን ለመጀመር ወደ ግራ ያንሸራትቱ።"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"የምግብር አርታዒውን ይክፈቱ"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ተከናውኗል"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ውቅረት"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ማከማቻ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ፍንጮች"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"የቅጽበት መተግበሪያዎች"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> አሂድ"</string> <string name="instant_apps_message" msgid="6112428971833011754">"መተግበሪያ ሳይጫን ተከፍቷል።"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"የተደራሽነት ባህሪያትን ለመክፈት መታ ያድርጉ። ይህንን አዝራር በቅንብሮች ውስጥ ያብጁ ወይም ይተኩ።\n\n"<annotation id="link">"ቅንብሮችን አሳይ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ለጊዜው ለመደበቅ አዝራሩን ወደ ጠርዝ ያንቀሳቅሱ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ቀልብስ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> አቋራጭ ተወግዷል"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# አቋራጭ ተወግዷል}one{# አቋራጭ ተወግዷል}other{# አቋራጮች ተወግደዋል}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ወደ ላይኛው ግራ አንቀሳቅስ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"የተጠቃሚ ተገኝነት ታውቋል"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string> <string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ለመቀጠል ያንሸራትቱ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"የውስጥ ማሳያዎ ይንጸባረቃል። የፊት ማሳያዎ ይጠፋል።"</string> <string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index d19c77b72eff..2566df7430d1 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"تعذّر إعداد ميزة \"فتح الجهاز بالتعرّف على الوجه\". انتقِل إلى \"الإعدادات\" لإعادة المحاولة."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"المس أداة استشعار بصمة الإصبع"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"للمتابعة، اضغط على رمز فتح القفل."</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"يتعذّر التعرّف على الوجه. استخدِم بصمة الإصبع بدلاً من ذلك."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"يتعذّر التعرّف على الوجه."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"يمكنك استخدام بصمة إصبعك."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ميزة \"فتح الجهاز بالتعرف على الوجه\" غير متاحة."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • جارٍ الشحن • ستمتلئ البطارية خلال <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"مرِّر سريعًا لليمين لبدء الدليل التوجيهي العام."</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"فتح محرِّر التطبيقات المصغّرة"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تم"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"عملية الإعداد"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"مساحة التخزين"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"تلميحات"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"التطبيقات الفورية"</string> <string name="instant_apps_title" msgid="8942706782103036910">"التطبيق <xliff:g id="APP">%1$s</xliff:g> قيد التشغيل"</string> <string name="instant_apps_message" msgid="6112428971833011754">"تمّ فتح التطبيق بدون تثبيته."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"انقر لفتح ميزات تسهيل الاستخدام. يمكنك تخصيص هذا الزر أو استبداله من الإعدادات.\n\n"<annotation id="link">"عرض الإعدادات"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"يمكنك نقل الزر إلى الحافة لإخفائه مؤقتًا."</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"تراجع"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"تمت إزالة اختصار <xliff:g id="FEATURE_NAME">%s</xliff:g>."</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{تمت إزالة اختصار واحد.}zero{تمت إزالة # اختصار.}two{تمت إزالة اختصارَين.}few{تمت إزالة # اختصارات.}many{تمت إزالة # اختصارًا.}other{تمت إزالة # اختصار.}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"النقل إلى أعلى يمين الشاشة"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"تم رصد تواجد المستخدم."</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string> <string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"مرِّر سريعًا للمتابعة."</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"سيتم النسخ المطابق لمحتوى الشاشة الداخلية، وإيقاف الشاشة الأمامية."</string> <string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 4e78f55663df..591c125cc90d 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ফে’চ আনলক ছেট আপ কৰিব পৰা নগ’ল। পুনৰ চেষ্টা কৰিবলৈ ছেটিঙলৈ যাওক।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"অব্যাহত ৰাখিবলৈ আনলক কৰক চিহ্নটোত টিপক"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখাৱয়ব চিনিব নোৱাৰি। ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক।"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"মুখাৱয়ব চিনিব নোৱাৰি"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ইয়াৰ সলনি ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ফেচ আনলক সুবিধা উপলব্ধ নহয়"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযোগ হ’ল।"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চাৰ্জ হৈ আছে • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ত সম্পূৰ্ণ হ’ব"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"সম্প্ৰদায় সম্পৰ্কীয় নিৰ্দেশনা আৰম্ভ কৰিবলৈ বাওঁফালে ছোৱাইপ কৰক"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ৱিজেট সম্পাদকটো খোলক"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"কৰা হ’ল"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ছেটআপ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ষ্ট\'ৰেজ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ইংগিতবোৰ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> চলি আছে"</string> <string name="instant_apps_message" msgid="6112428971833011754">"এপ্টো ইনষ্ট\'ল নকৰাকৈ খোলা হৈছে।"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"সাধ্য সুবিধাসমূহ খুলিবলৈ টিপক। ছেটিঙত এই বুটামটো কাষ্টমাইজ অথবা সলনি কৰক।\n\n"<annotation id="link">"ছেটিং চাওক"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"বুটামটোক সাময়িকভাৱে লুকুৱাবলৈ ইয়াক একেবাৰে কাষলৈ লৈ যাওক"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"আনডু কৰক"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>ৰ শ্বৰ্টকাট আঁতৰোৱা হ’ল"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# টা শ্বৰ্টকাট আঁতৰোৱা হ’ল}one{# টা শ্বৰ্টকাট আঁতৰোৱা হ’ল}other{# টা শ্বৰ্টকাট আঁতৰোৱা হ’ল}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যৱহাৰকাৰীৰ উপস্থিতি চিনাক্ত কৰা হৈছে"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string> <string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"অব্যাহত ৰাখিবলৈ ছোৱাইপ কৰক"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপোনাৰ ইনাৰ ডিছপ্লে’ প্ৰতিবিম্বিত কৰা হ’ব। আপোনাৰ ফ্ৰণ্ট ডিছপ্লে’ অফ কৰা হ’ব।"</string> <string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index bf32c5e6eb0a..978c29500cff 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Üz ilə Kiliddən Açma ayarlanmadı. Yenidən cəhd etmək üçün Ayarlara keçin."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmaq izi sensoruna klikləyin"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"\"Kiliddən çıxarın\" ikonasını basaraq davam edin"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tanımaq olmur. Barmaq izini işlədin."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Üzü tanımaq olmur"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmaq izi istifadə edin"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Üz ilə kiliddən çıxarma əlçatan deyil"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth qoşulub."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj edilir • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> sonra dolacaq"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"İcma təlimatını başlatmaq üçün sola sürüşdürün"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidcet redaktorunu açın"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hazırdır"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Ayarlama"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Yaddaş"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Məsləhətlər"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Ani Tətbiqlər"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> işləyir"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Quraşdırılmadan açılan tətbiq."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Əlçatımlılıq funksiyalarını açmaq üçün toxunun. Ayarlarda bu düyməni fərdiləşdirin və ya dəyişdirin.\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Geri qaytarın"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> qısayol silindi"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# qısayol silindi}other{# qısayol silindi}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"İstifadəçi mövcudluğu aşkarlandı"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Çəkərək davam edin"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç displey əks etdiriləcək. Ön ekran deaktiv ediləcək."</string> <string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 56c3e45b4726..1668de0ee969 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Podešavanje otključavanja licem nije uspelo. Idite u Podešavanja da biste probali ponovo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pritisnite ikonu otključavanja za nastavak"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Lice nije prepoznato. Koristite otisak prsta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem nije dostupno"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je priključen."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Puni se • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do kraja punjenja"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prevucite ulevo da biste započeli zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvori uređivač vidžeta"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Podešavanje"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Memorijski prostor"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Saveti"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacija se otvorila bez instaliranja."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za funkcije pristupačnosti. Prilagodite ili zamenite ovo dugme u Podešavanjima.\n\n"<annotation id="link">"Podešavanja"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomerite dugme do ivice da biste ga privremeno sakrili"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Opozovi"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Prečica funkcije <xliff:g id="FEATURE_NAME">%s</xliff:g> je uklonjena"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# prečica je uklonjena}one{# prečica je uklonjena}few{# prečice su uklonjene}other{# prečica je uklonjeno}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premesti gore levo"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Prisustvo korisnika može da se otkrije"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da biste nastavili"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikati. Prednji ekran će se isključiti."</string> <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 3bc6269a71b0..8d2addad30fa 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не ўдалося наладзіць функцыю распазнавання твару. Каб паўтарыць, перайдзіце ў Налады."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Дакраніцеся да сканера адбіткаў пальцаў"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Каб працягнуць, націсніце на значок разблакіроўкі"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Твар не распазнаны. Скарыстайце адбітак пальца."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Твар не распазнаны"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скарыстайце адбітак пальца"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Распазнаванне твару не працуе"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-сувязь."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ідзе зарадка • Поўны зарад праз <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Правядзіце пальцам па экране ўлева, каб азнаёміцца з дапаможнікам"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Адкрыць рэдактар віджэтаў"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Гатова"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Наладжванне"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Захоўванне"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Падказкі"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Імгненныя праграмы"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" запушчана"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Праграма адкрыта без усталёўкі."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Націсніце, каб адкрыць спецыяльныя магчымасці. Рэгулюйце ці замяняйце кнопку ў Наладах.\n\n"<annotation id="link">"Прагляд налад"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Каб часова схаваць кнопку, перамясціце яе на край"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Адрабіць"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Выдалены ярлык <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Выдалены # ярлык}one{Выдалены # ярлык}few{Выдалена # ярлыкі}many{Выдалена # ярлыкоў}other{Выдалена # ярлыка}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перамясціць лявей і вышэй"</string> @@ -1207,9 +1225,9 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Выяўлена прысутнасць карыстальніка"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string> <string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Правядзіце пальцам, каб працягнуць"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплэі?"</string> - <!-- no translation found for connected_display_dialog_dual_display_stop_warning (4174707498892447947) --> - <skip /> + <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Будзе ўключана дубліраванне ўнутранага дысплэя. Пярэдні дысплэй будзе выключаны."</string> <string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"Закрыць"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"Дысплэй падключаны"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 22d167ee50db..6f5890fac679 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Функцията „Отключване с лице“ не бе настроена. Отворете настройките, за да опитате отново."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Докоснете сензора за отпечатъци"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Натиснете иконата за отключване, за да продължите"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лицето не е разпознато. Използвайте отпечатък."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицето не е разпознато"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Използвайте отпечатък"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"„Отключване с лице“ не е налице"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е включен."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарежда се • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до пълно зареждане"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Прекарайте пръст наляво, за да стартирате общия урок"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Отваряне на редактора на приспособлението"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Настройване"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Съвети"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Мигновени приложения"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> работи"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Приложението се отвори, без да бъде инсталирано."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Докоснете, за да отворите функциите за достъпност. Персон./заменете бутона от настройките.\n\n"<annotation id="link">"Преглед на настройките"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете бутона до края, за да го скриете временно"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Отмяна"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Прекият път за „<xliff:g id="FEATURE_NAME">%s</xliff:g>“ бе премахнат"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# пряк път бе премахнат}other{# преки пътя бяха премахнати}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Преместване горе вляво"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Установено е присъствие на потребител"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string> <string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Прекарайте пръст, за да продължите"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Съдържанието на вътрешния ви дисплей ще бъде дублирано. Предният ви дисплей ще бъде изключен."</string> <string name="mirror_display" msgid="2515262008898122928">"Дублиране на дисплея"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 045af935be6c..601b29afa911 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"\'ফেস আনলক\' সেট-আপ করা যায়নি। আবার চেষ্টা করতে সেটিংসে যান।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"আঙ্গুলের ছাপের সেন্সর স্পর্শ করুন"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"চালিয়ে যেতে \'আনলক করুন\' আইকনে প্রেস করুন"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"মুখ শনাক্ত করতে পারছি না। পরিবর্তে আঙ্গুলের ছাপ ব্যবহার করুন।"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ফেস শনাক্ত করা যায়নি"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"পরিবর্তে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\'ফেস আনলক\' উপলভ্য নেই"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ব্লুটুথ সংযুক্ত হয়েছে৷"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • চার্জ হচ্ছে • পুরো চার্জ হতে আরও <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> সময় লাগবে"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"কমিউনিটি টিউটোরিয়াল চালু করতে বাঁদিকে সোয়াইপ করুন"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"উইজেট এডিটর খুলুন"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"হয়ে গেছে"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"সেট-আপ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"স্টোরেজ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"হিন্ট"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> চলছে"</string> <string name="instant_apps_message" msgid="6112428971833011754">"অ্যাপটি ইনস্টল না করে চালু করা হয়েছে।"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"অ্যাক্সেসিবিলিটি ফিচার খুলতে ট্যাপ করুন। কাস্টমাইজ করুন বা সেটিংসে এই বোতামটি সরিয়ে দিন।\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"আগের অবস্থায় ফিরুন"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>-এর শর্টকাট সরানো হয়েছে"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{#টি শর্টকাট সরানো হয়েছে}one{#টি শর্টকাট সরানো হয়েছে}other{#টি শর্টকাট সরানো হয়েছে}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যবহারকারীর উপস্থিতি শনাক্ত করা হয়েছে"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string> <string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"চালিয়ে যেতে সোয়াইপ করুন"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লেতে মিরর করবেন?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপনার ইনার ডিসপ্লে মিরর করা হবে। আপনার ফ্রন্ট ডিসপ্লে বন্ধ করা হবে।"</string> <string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index ae962ce7ead5..287eed74032c 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Postavljanje otključavanja licem nije uspjelo. Idite u Postavke da pokušate ponovo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor za otisak prsta"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Nastavak pritiskanjem ikone za otključavanje"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nije moguće prepoznati lice. Koristite otisak prsta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Nije moguće prepoznati lice"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Koristite otisak prsta"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem je nedostupno"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth je povezan."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Punjenje • Potpuna napunjenost za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prevucite ulijevo da pokrenete zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvaranje uređivača vidžeta"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Postavljanje"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacija je otvorena bez prethodne instalacije."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite da otvorite funkcije pristupačnosti. Prilagodite ili zamijenite dugme u Postavkama.\n\n"<annotation id="link">"Postavke"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Premjestite dugme do ivice da ga privremeno sakrijete"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Opozovi"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Prečica <xliff:g id="FEATURE_NAME">%s</xliff:g> je uklonjena"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# prečica je uklonjena}one{# prečica je uklonjena}few{# prečice su uklonjene}other{# prečica je uklonjeno}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pomjeranje gore lijevo"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkriveno je prisustvo korisnika"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da nastavite"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikavati. Prednji ekran će se isključiti."</string> <string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 8cf88282d646..d56e4f0d14c5 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"No s\'ha pogut configurar el desbloqueig facial. Ves a Configuració per tornar-ho a provar."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor d\'empremtes digitals"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Prem la icona de desbloqueig per continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No podem detectar la cara. Usa l\'empremta digital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"No es reconeix la cara"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilitza l\'empremta digital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueig facial no està disponible"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connectat."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • S\'està carregant • Es completarà d\'aquí a <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Llisca cap a l\'esquerra per iniciar el tutorial de la comunitat"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Obre l\'editor de widgets"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fet"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuració"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Emmagatzematge"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Suggeriments"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplicacions instantànies"</string> <string name="instant_apps_title" msgid="8942706782103036910">"S\'està executant <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"L\'aplicació s\'ha obert sense instal·lar-se."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca per obrir funcions d\'accessibilitat. Personalitza o substitueix el botó a Configuració.\n\n"<annotation id="link">"Mostra"</annotation>"."</string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mou el botó a l\'extrem per amagar-lo temporalment"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Desfés"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"S\'ha suprimit la drecera a <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{S\'ha suprimit # drecera}many{S\'han suprimit # dreceres}other{S\'han suprimit # dreceres}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mou a dalt a l\'esquerra"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"S\'ha detectat la presència d\'usuaris"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string> <string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Llisca per continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Duplicar a la pantalla externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"La pantalla interior es duplicarà. La pantalla frontal es desactivarà."</string> <string name="mirror_display" msgid="2515262008898122928">"Duplica la pantalla"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 17084dc4c543..9c7143608678 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Odemknutí obličejem se nepodařilo nastavit. Pokud to chcete zkusit znovu, přejděte do Nastavení."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotkněte se snímače otisků prstů"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Klepněte na ikonu odemknutí"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obličej se nepodařilo rozpoznat. Použijte místo něj otisk prstu."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Obličej nelze rozpoznat"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Použijte otisk prstu"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odemknutí obličejem není k dispozici"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Rozhraní Bluetooth je připojeno."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíjení • Plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Přejetím doleva spustíte komunitní výukový program"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otevřít editor widgetů"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavit"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Úložiště"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikace"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Aplikace <xliff:g id="APP">%1$s</xliff:g> je spuštěna"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikace byla otevřena bez instalace."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Klepnutím otevřete funkce přístupnosti. Tlačítko lze upravit nebo nahradit v Nastavení.\n\n"<annotation id="link">"Nastavení"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Přesunutím tlačítka k okraji ho dočasně skryjete"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Vrátit zpět"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Zkratka pro <xliff:g id="FEATURE_NAME">%s</xliff:g> byla odstraněna"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Byla odstraněna # zkratka}few{Byly odstraněny # zkratky}many{Bylo odstraněno # zkratky}other{Bylo odstraněno # zkratek}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Přesunout vlevo nahoru"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Je zjištěna přítomnost uživatele"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string> <string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte přejetím prstem"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnitřní displej bude zrcadlen. Přední displej bude vypnutý."</string> <string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 41abea3a51c8..06f9ff327d87 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ansigtsoplåsning kunne ikke konfigureres. Gå til Indstillinger for at prøve igen."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sæt fingeren på fingeraftrykssensoren"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tryk på oplåsningsikonet for at fortsætte"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansigtet kan ikke genkendes. Brug fingeraftryk i stedet."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansigt kan ikke genkendes"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Brug fingeraftryk i stedet"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansigtsoplåsning er utilgængelig"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tilsluttet."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Oplader • Fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Stryg mod venstre for at starte den fælles vejledning"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Åbn redigeringsværktøjet til widgets"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Udfør"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfiguration"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Lagerplads"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> kører"</string> <string name="instant_apps_message" msgid="6112428971833011754">"En app blev åbnet uden at blive installeret."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryk for at åbne hjælpefunktioner. Tilpas eller erstat denne knap i Indstillinger.\n\n"<annotation id="link">"Se indstillingerne"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flyt knappen til kanten for at skjule den midlertidigt"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Fortryd"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Genvejen til <xliff:g id="FEATURE_NAME">%s</xliff:g> er fjernet"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# genvej er fjernet}one{# genvej er fjernet}other{# genveje er fjernet}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flyt op til venstre"</string> @@ -1033,7 +1051,7 @@ <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Åbn appen for at caste denne session."</string> <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Ukendt app"</string> <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Stop med at caste"</string> - <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheder, der er tilgængelige for lydoutput."</string> + <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Enheder, der er tilgængelige for lydudgang."</string> <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Lydstyrke"</string> <string name="media_output_dialog_volume_percentage" msgid="1613984910585111798">"<xliff:g id="PERCENTAGE">%1$d</xliff:g> %%"</string> <string name="media_output_group_title_speakers_and_displays" msgid="7169712332365659820">"Højttalere og skærme"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Brugertilstedeværelse er registreret"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Stryg for at fortsætte"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Din indre skærm spejles. Din skærm på forsiden slukkes."</string> <string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index d95e229c2e9b..2acd2feaa879 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Die Entsperrung per Gesichtserkennung konnte nicht eingerichtet werden. Gehe zu den Einstellungen und versuche es noch einmal."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Berühre den Fingerabdrucksensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tippe zum Fortfahren auf das Symbol „Entsperren“"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gesicht wurde nicht erkannt. Verwende stattdessen den Fingerabdruck."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Gesicht nicht erkannt"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Fingerabdruck verwenden"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Entsperrung per Gesichtserkennung nicht verfügbar"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Mit Bluetooth verbunden"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Wird geladen • Voll in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Wische nach links, um das gemeinsame Tutorial zu starten"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Widget-Editor öffnen"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fertig"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Einrichtung"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Speicher"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hinweise"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> wird ausgeführt"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App wurde geöffnet, ohne vorher installiert zu werden."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tippe, um die Bedienungshilfen aufzurufen. Du kannst diese Schaltfläche in den Einstellungen anpassen oder ersetzen.\n\n"<annotation id="link">"Zu den Einstellungen"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Rückgängig machen"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Verknüpfung für „<xliff:g id="FEATURE_NAME">%s</xliff:g>“ entfernt"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# Verknüpfung entfernt}other{# Verknüpfungen entfernt}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Anwesenheit des Nutzers wurde erkannt"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string> <string name="install_app" msgid="5066668100199613936">"App installieren"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Zum Fortfahren wischen"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Dein inneres Display wird gespiegelt. Das Frontdisplay wird ausgeschaltet."</string> <string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 5848e4ff460a..79d350b16300 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Δεν ήταν δυνατή η ρύθμιση για το Ξεκλείδωμα με το πρόσωπο. Μεταβείτε στις Ρυθμίσεις και δοκιμάστε ξανά."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Αγγίξτε τον αισθητήρα δακτυλικού αποτυπώματος"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Πατήστε το εικονίδιο ξεκλειδώματος για συνέχεια"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Το πρόσωπο δεν αναγνωρίζεται. Χρησιμ. δακτ. αποτ."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Αδύνατη η αναγν. προσώπου"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Χρησιμ. δακτυλ. αποτύπ."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ξεκλ. με πρόσωπο μη διαθ."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Το Bluetooth είναι συνδεδεμένο."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Φόρτιση • Πλήρης φόρτιση σε <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Σύρετε προς τα αριστερά για να ξεκινήσετε τον κοινόχρηστο οδηγό"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Άνοιγμα προγράμ. επεξεργασίας γραφικών στοιχείων"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Τέλος"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Ρύθμιση"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Αποθηκευτικός χώρος"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Συμβουλές"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Εφαρμογές"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Η εφαρμογή άνοιξε χωρίς να έχει εγκατασταθεί."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Πατήστε για άνοιγμα των λειτουργιών προσβασιμότητας. Προσαρμόστε ή αντικαταστήστε το κουμπί στις Ρυθμίσεις.\n\n"<annotation id="link">"Προβολή ρυθμίσεων"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Μετακινήστε το κουμπί στο άκρο για προσωρινή απόκρυψη"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Αναίρεση"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Η συντόμευση <xliff:g id="FEATURE_NAME">%s</xliff:g> καταργήθηκε"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Καταργήθηκε # συντόμευση}other{Καταργήθηκαν # συντομεύσεις}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Μετακίνηση επάνω αριστερά"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Εντοπίστηκε παρουσία χρήστη"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string> <string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Σύρετε για συνέχεια"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Θα γίνει κατοπτρισμός της εσωτερικής προβολής. Η μπροστινή οθόνη θα απενεργοποιηθεί."</string> <string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 870e4dd499b3..afd2e728aa68 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Couldn\'t set up Face Unlock. Go to Settings to try again."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Press the unlock icon to continue"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe left to start the communal tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Open the widget editor"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> running"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App opened without being installed."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut removed"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut removed}other{# shortcuts removed}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index f25baf286ba0..a0000efbd607 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -188,10 +188,10 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Couldn’t set up face unlock. Go to Settings to try again."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Press the unlock icon to continue"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognize face. Use fingerprint instead."</string> + <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"Face not recognized. Use fingerprint instead."</string> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognize face"</string> + <string name="keyguard_face_failed" msgid="2346762871330729634">"Face not recognized"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> @@ -413,6 +413,11 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe left to start the communal tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Open the widget editor"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Customize"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Dismiss"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove, and reorder your widgets in this space"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string> + <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string> @@ -834,6 +839,7 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <string name="notification_channel_accessibility" msgid="8956203986976245820">"Accessibility"</string> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> running"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App opened without being installed."</string> @@ -929,6 +935,8 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string> + <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"Accessibility button hidden"</string> + <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"Tap to show accessibility button"</string> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut removed"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut removed}other{# shortcuts removed}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string> @@ -1207,6 +1215,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 870e4dd499b3..afd2e728aa68 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Couldn\'t set up Face Unlock. Go to Settings to try again."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Press the unlock icon to continue"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe left to start the communal tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Open the widget editor"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> running"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App opened without being installed."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut removed"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut removed}other{# shortcuts removed}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 870e4dd499b3..afd2e728aa68 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Couldn\'t set up Face Unlock. Go to Settings to try again."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Press the unlock icon to continue"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognise face. Use fingerprint instead."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognise face"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe left to start the communal tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Open the widget editor"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> running"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App opened without being installed."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut removed"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut removed}other{# shortcuts removed}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index b3ed7145c9b8..835cf38556bc 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -188,10 +188,10 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Couldn’t set up face unlock. Go to Settings to try again."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touch the fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Press the unlock icon to continue"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Can’t recognize face. Use fingerprint instead."</string> + <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"Face not recognized. Use fingerprint instead."</string> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Can’t recognize face"</string> + <string name="keyguard_face_failed" msgid="2346762871330729634">"Face not recognized"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use fingerprint instead"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Face Unlock unavailable"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connected."</string> @@ -413,6 +413,11 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Charging • Full in <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe left to start the communal tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Open the widget editor"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Customize"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Dismiss"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove, and reorder your widgets in this space"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string> + <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string> @@ -834,6 +839,7 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <string name="notification_channel_accessibility" msgid="8956203986976245820">"Accessibility"</string> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> running"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App opened without being installed."</string> @@ -929,6 +935,8 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation>""</string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string> + <string name="accessibility_floating_button_hidden_notification_title" msgid="4115036997406994799">"Accessibility button hidden"</string> + <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"Tap to show accessibility button"</string> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut removed"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut removed}other{# shortcuts removed}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string> @@ -1207,6 +1215,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string> <string name="install_app" msgid="5066668100199613936">"Install app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string> <string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index c5355605fe17..a12c574c2c37 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"No se pudo configurar el desbloqueo facial. Ve a Configuración para volver a intentarlo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas dactilares"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Presiona el ícono de desbloqueo para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce el rostro. Usa la huella dactilar."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce el rostro"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella dactilar"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueo facial no disponible"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • Se completará en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Desliza el dedo a la izquierda para iniciar el instructivo comunal"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir el editor de widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Listo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuración"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Apps instantáneas"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string> <string name="instant_apps_message" msgid="6112428971833011754">"La app se abrió sin instalarse."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Presiona para abrir las funciones de accesibilidad. Personaliza o cambia botón en Config.\n\n"<annotation id="link">"Ver config"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Deshacer"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Se quitó el acceso directo a <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Se quitó # acceso directo}many{Se quitaron # accesos directos}other{Se quitaron # accesos directos}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se detectó la presencia del usuario"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza el dedo para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar en la pantalla externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se duplicará la pantalla interior. Se apagará la pantalla frontal."</string> <string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 1157ff1933ba..765f2e3e9479 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"No se ha podido configurar Desbloqueo facial. Ve a Ajustes e inténtalo de nuevo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca el sensor de huellas digitales"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pulsa el icono de desbloquear para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"No se reconoce la cara. Usa la huella digital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"No se reconoce la cara"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa la huella digital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueo facial no disponible"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • Carga completa en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Desliza hacia la izquierda para iniciar el tutorial de la comunidad"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir editor de widgets"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hecho"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuración"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamiento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Sugerencias"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplicaciones Instantáneas"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> se está ejecutando"</string> <string name="instant_apps_message" msgid="6112428971833011754">"La aplicación se ha abierto sin instalarse."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir funciones de accesibilidad. Personaliza o sustituye este botón en Ajustes.\n\n"<annotation id="link">"Ver ajustes"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Deshacer"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Acceso directo a <xliff:g id="FEATURE_NAME">%s</xliff:g> quitado"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# acceso directo eliminado}many{# accesos directos eliminados}other{# accesos directos eliminados}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Se ha detectado la presencia de usuarios"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Proyectar a pantalla externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se proyectará tu pantalla interior. Se apagará tu pantalla frontal."</string> <string name="mirror_display" msgid="2515262008898122928">"Proyectar pantalla"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 36b3f1e219e2..249e45f0c650 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Näoga avamist ei õnnestunud seadistada. Avage seaded ja proovige uuesti."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Puudutage sõrmejäljeandurit"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Jätkamiseks vajutage avamise ikooni"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nägu ei õnnestu tuvastada. Kasutage sõrmejälge."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Nägu ei õnnestu tuvastada"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kasutage sõrmejälge"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Näoga avamine pole saadaval"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth on ühendatud."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laadimine • Täis <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> pärast"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ühise õpetuse käivitamiseks pühkige vasakule"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidina redaktori avamine"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Seadistamine"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Salvestusruum"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Vihjed"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Installimata avatavad rakendused"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Rakendus <xliff:g id="APP">%1$s</xliff:g> töötab"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Rakendus avati installimata."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Puudutage juurdepääsufunktsioonide avamiseks. Kohandage nuppu või asendage see seadetes.\n\n"<annotation id="link">"Kuva seaded"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Teisaldage nupp serva, et see ajutiselt peita"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Võta tagasi"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Funktsiooni <xliff:g id="FEATURE_NAME">%s</xliff:g> otsetee eemaldati"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# otsetee eemaldati}other{# otseteed eemaldati}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Teisalda üles vasakule"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Tuvastati kasutaja kohalolu"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string> <string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pühkige jätkamiseks"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Teie siseekraani peegeldatakse. Teie esiekraan lülitatakse välja."</string> <string name="mirror_display" msgid="2515262008898122928">"Peegelda ekraani"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 5ea02d173fcb..1a0d482a14a9 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ezin izan da konfiguratu aurpegi bidez desblokeatzeko eginbidea. Berriro saiatzeko, joan ezarpenetara."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sakatu hatz-marken sentsorea"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Aurrera egiteko, sakatu desblokeatzeko ikonoa"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ezin da hauteman aurpegia. Erabili hatz-marka."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Ezin da ezagutu aurpegia"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Erabili hatz-marka"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Aurpegi bidez desblokeatzeko eginbidea ez dago erabilgarri"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetootha konektatuta."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Kargatzen • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> guztiz kargatu arte"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Tutorial komuna hasteko, pasatu hatza ezkerrera"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ireki widget-editorea"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Eginda"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurazioa"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Memoria"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Aholkuak"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Zuzeneko aplikazioak"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> abian da"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Ezer instalatu gabe ireki da aplikazioa."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erabilerraztasun-eginbideak irekitzeko, sakatu hau. Ezarpenetan pertsonalizatu edo ordez dezakezu botoia.\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Eraman botoia ertzera aldi baterako ezkutatzeko"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Desegin"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Kendu da lasterbidea (<xliff:g id="FEATURE_NAME">%s</xliff:g>)"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# lasterbide kendu da}other{# lasterbide kendu dira}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Eraman goialdera, ezkerretara"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Erabiltzailearen presentzia hauteman da"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string> <string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Aurrera egiteko, pasatu hatza"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Barneko pantaila islatuko da. Aurreko pantaila desaktibatu egingo da."</string> <string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index aa77b4b4ddb7..b77c94972fb8 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"«قفلگشایی با چهره» راهاندازی نشد. برای امتحان مجدد، به «تنظیمات» بروید."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"حسگر اثر انگشت را لمس کنید"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"برای ادامه، نماد قفلگشایی را فشار دهید"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چهره شناسایی نشد. درعوض از اثر انگشت استفاده کنید."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"چهره شناسایی نشد"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"از اثر انگشت استفاده کنید"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"«قفلگشایی با چهره» دردسترس نیست"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوتوث متصل است."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • درحال شارژ شدن • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> تا شارژ کامل"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"برای شروع آموزش گامبهگام عمومی، تند بهچپ بکشید"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"باز کردن ویرایشگر ابزارک"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تمام"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"راهاندازی"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"فضای ذخیرهسازی"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"نکات"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"برنامههای فوری"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> درحال اجرا"</string> <string name="instant_apps_message" msgid="6112428971833011754">"برنامه بدون نصب شدن باز شد."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"برای باز کردن ویژگیهای دسترسپذیری ضربه بزنید. در تنظیمات این دکمه را سفارشی یا جایگزین کنید\n\n"<annotation id="link">"تنظیمات"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"برای پنهان کردن موقتی دکمه، آن را به لبه ببرید"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"واگرد"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"میانبر «<xliff:g id="FEATURE_NAME">%s</xliff:g>» برداشته شد"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{میانبر «#» برداشته شد}one{میانبر «#» برداشته شد}other{میانبر «#» برداشته شد}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"انتقال به بالا سمت راست"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"حضور کاربر شناسایی میشود"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string> <string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"برای ادامه، تند بکشید"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"روی نمایشگر خارجی قرینهسازی شود؟"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"نمایشگر داخلی شما قرینهسازی میشود. نمایشگر جلو خاموش میشود."</string> <string name="mirror_display" msgid="2515262008898122928">"قرینهسازی نمایشگر"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 882c42c3f848..b764e07dea93 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Kasvojentunnistusavauksen käyttöönotto epäonnistui. Siirry asetuksiin ja yritä uudelleen."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Kosketa sormenjälkitunnistinta"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Jatka lukituksen avauskuvakkeella"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Kasvoja ei voi tunnistaa. Käytä sormenjälkeä."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Kasvoja ei voi tunnistaa"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Käytä sormenjälkeä"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Kasvojentunnistusavaus ei ole saatavilla"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth yhdistetty."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Latautuu • Täynnä <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> päästä"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Aloita yhteisöesittely pyyhkäisemällä vasemmalle"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Avaa widgetien muokkaaja"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Määritys"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Tallennustila"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Vihjeet"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> on käynnissä"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Sovellus avattiin ilman asennusta."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Avaa esteettömyysominaisuudet napauttamalla. Yksilöi tai vaihda painike asetuksista.\n\n"<annotation id="link">"Avaa asetukset"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Piilota painike tilapäisesti siirtämällä se reunaan"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Kumoa"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Pikanäppäin (<xliff:g id="FEATURE_NAME">%s</xliff:g>) poistettu"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# pikanäppäin poistettu}other{# pikanäppäintä poistettu}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Siirrä vasempaan yläreunaan"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Käyttäjän läsnäolo havaittu"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string> <string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Jatka pyyhkäisemällä"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Sisänäyttö peilataan. Etunäyttö laitetaan pois päältä."</string> <string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 8370b01ccfd5..68f69a602e2a 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Impossible de configurer le Déverrouillage par reconnaissance faciale. Accédez au menu Paramètres pour réessayer."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Touchez le capteur d\'empreintes digitales"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Appuyez sur l\'icône Déverrouiller pour continuer"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez plutôt l\'empreinte digitale."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utiliser l\'empreinte digitale"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Déverrouillage par reconnaissance faciale inaccessible."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge en cours… • Se terminera dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Balayer l\'écran vers la gauche pour démarrer le tutoriel communautaire"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ouvrir l\'éditeur de widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuration"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Stockage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Conseils"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Applications instantanées"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Application ouverte sans avoir été installée."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Touchez pour ouvrir fonction. d\'access. Personnalisez ou remplacez bouton dans Param.\n\n"<annotation id="link">"Afficher param."</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Annuler"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Le raccourci <xliff:g id="FEATURE_NAME">%s</xliff:g> a été retiré"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# raccourci retiré}one{# raccourci retiré}many{# de raccourcis retirés}other{# raccourcis retirés}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayez l\'écran pour continuer"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera désactivé."</string> <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index af81a31002a4..0c8ef28ed444 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Impossible de configurer le déverrouillage par reconnaissance faciale. Accédez aux paramètres pour réessayer."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Appuyez sur le lecteur d\'empreinte digitale"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Appuyez sur l\'icône de déverrouillage pour continuer"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Visage non reconnu. Utilisez votre empreinte."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Visage non reconnu"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Utilisez empreinte digit."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Déverrouillage par reconnaissance faciale indisponible"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth connecté"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Temps restant : <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Balayer vers la gauche pour démarrer le tutoriel collectif"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Ouvrir l\'éditeur de widgets"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"OK"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurer"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Espace de stockage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Astuces"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Applis instantanées"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> en cours d\'exécution"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Vous pouvez ouvrir cette application sans l\'installer."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Appuyez pour ouvrir fonctionnalités d\'accessibilité. Personnalisez ou remplacez bouton dans paramètres.\n\n"<annotation id="link">"Voir paramètres"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacer le bouton vers le bord pour le masquer temporairement"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Annuler"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Raccourci vers <xliff:g id="FEATURE_NAME">%s</xliff:g> supprimé"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# raccourci supprimé}one{# raccourci supprimé}many{# raccourcis supprimés}other{# raccourcis supprimés}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence de l\'utilisateur est détectée"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string> <string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayer pour continuer"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer sur l\'écran externe ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera éteint."</string> <string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index ef0751b8f0c4..a705f2aec70e 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Non se puido configurar o desbloqueo facial. Para tentalo de novo, vai a Configuración."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toca o sensor de impresión dixital"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Preme a icona de desbloquear para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Non se recoñeceu a cara. Usa a impresión dixital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Non se recoñeceu a cara"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa a impresión dixital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O desbloqueo facial non está dispoñible"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Cargando • A carga completarase en <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Pasa o dedo cara á esquerda para iniciar o titorial comunitario"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Feito"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Almacenamento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Consellos"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplicacións Instantáneas"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Estase executando <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Abriuse a aplicación sen ter que instalala."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir as funcións de accesibilidade. Cambia este botón en Configuración.\n\n"<annotation id="link">"Ver configuración"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Para ocultar temporalmente o botón, móveo ata o bordo"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Desfacer"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Quitouse o atallo de <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Quitouse # atallo}other{Quitáronse # atallos}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover á parte super. esquerda"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Detectouse a presenza de usuarios"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string> <string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pasa o dedo para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Proxectarase a pantalla interior. Desactivarase a pantalla frontal."</string> <string name="mirror_display" msgid="2515262008898122928">"Proxectar pantalla"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index d92231c9bf93..9965f450c565 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ફેસ અનલૉક સુવિધાનું સેટઅપ કરી શક્યા નથી. ફરી પ્રયાસ કરવા માટે સેટિંગ પર જાઓ."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ફિંગરપ્રિન્ટના સેન્સરને સ્પર્શ કરો"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ચાલુ રાખવા \'અનલૉક કરો\' આઇકન દબાવો"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ચહેરો ઓળખી શકતા નથી. તેને બદલે ફિંગરપ્રિન્ટ વાપરો."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ચહેરો ઓળખાતો નથી"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"તો ફિંગરપ્રિન્ટ વાપરો"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ફેસ અનલૉક સુવિધા ઉપલબ્ધ નથી"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"બ્લૂટૂથ કનેક્ટ થયું."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ચાર્જ થઈ રહ્યું છે • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>માં પૂરું ચાર્જ થઈ જશે"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"કૉમ્યુનલ ટ્યૂટૉરિઅલ શરૂ કરવા માટે ડાબે સ્વાઇપ કરો"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"વિજેટ એડિટર ખોલો"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"થઈ ગયું"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"સેટઅપ કરો"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"સ્ટોરેજ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"હિન્ટ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ચાલી રહી છે"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ઍપ ઇન્સ્ટૉલ કર્યા વિના ખુલી જાય છે."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ઍક્સેસિબિલિટી સુવિધાઓ ખોલવા માટે ટૅપ કરો. સેટિંગમાં આ બટનને કસ્ટમાઇઝ કરો અથવા બદલો.\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"છેલ્લો ફેરફાર રદ કરો"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> શૉર્ટકટ કાઢી નાખ્યો"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# શૉર્ટકટ કાઢી નાખ્યો}one{# શૉર્ટકટ કાઢી નાખ્યો}other{# શૉર્ટકટ કાઢી નાખ્યા}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"વપરાશકર્તાની હાજરીની ભાળ મળી છે"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string> <string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ચાલુ રાખવા સ્વાઇપ કરો"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"તમારું ઇનર ડિસ્પ્લે મિરર કરવામાં આવશે. તમારું ફ્રન્ટ ડિસ્પ્લે બંધ કરવામાં આવશે."</string> <string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index f8c78a908433..e2ed3abb92cd 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"फ़ेस अनलॉक की सुविधा सेट अप नहीं की जा सकी. सेटिंग पर जाकर दोबारा कोशिश करें."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फ़िंगरप्रिंट सेंसर को छुएं"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"जारी रखने के लिए अनलॉक आइकॉन पर टैप करें"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरे की पहचान नहीं हुई. फ़िंगरप्रिंट इस्तेमाल करें."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरे की पहचान नहीं हुई"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"फ़िंगरप्रिंट इस्तेमाल करें"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फ़ेस अनलॉक की सुविधा उपलब्ध नहीं है"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट किया गया."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हो रहा है • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> में पूरा चार्ज हो जाएगा"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"कम्यूनिटी ट्यूटोरियल शुरू करने के लिए, बाईं ओर स्वाइप करें"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट एडिटर खोलें"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"हो गया"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"सेट अप"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"संकेत"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> चल रहा है"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ऐप्लिकेशन इंस्टॉल किए बिना ही खुल गया है."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सुलभता सुविधाएं खोलने के लिए टैप करें. सेटिंग में, इस बटन को बदलें या अपने हिसाब से सेट करें.\n\n"<annotation id="link">"सेटिंग देखें"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटन को कुछ समय छिपाने के लिए, उसे किनारे पर ले जाएं"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"पहले जैसा करें"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> का शॉर्टकट हटाया गया"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# शॉर्टकट हटाया गया}one{# शॉर्टकट हटाया गया}other{# शॉर्टकट हटाए गए}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सबसे ऊपर बाईं ओर ले जाएं"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"उपयोगकर्ता की मौजूदगी का पता लगाया गया"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string> <string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी रखने के लिए स्वाइप करें"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर डिसप्ले करना है?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"आपके फ़ोन के इनर डिसप्ले की स्क्रीन शेयर की जाएगी. फ़्रंट डिसप्ले को बंद कर दिया जाएगा."</string> <string name="mirror_display" msgid="2515262008898122928">"डिसप्ले करें"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 0803aeb7d1a3..f5d73eadf3da 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Postavljanje otključavanja licem nije uspjelo. Pokušajte ponovo u postavkama."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dodirnite senzor otiska prsta"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pritisnite ikonu otključavanja da biste nastavili"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Prepoznavanje lica nije uspjelo. Upotrijebite otisak prsta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Lice nije prepoznato"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Upotrijebite otisak prsta"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Otključavanje licem nije dostupno"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth povezan."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • punjenje • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> do napunjenosti"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Prijeđite prstom ulijevo da biste pokrenuli zajednički vodič"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvaranje alata za uređivanje widgeta"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Postavljanje"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Pohrana"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Savjeti"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant aplikacije"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Izvodi se aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacija je otvorena bez instaliranja."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za otvaranje značajki pristupačnosti. Prilagodite ili zamijenite taj gumb u postavkama.\n\n"<annotation id="link">"Pregledajte postavke"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomaknite gumb do ruba da biste ga privremeno sakrili"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Poništi"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Uklonjen je prečac za uslugu <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Uklonjen je # prečac}one{Uklonjen je # prečac}few{Uklonjena su # prečaca}other{Uklonjeno je # prečaca}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premjesti u gornji lijevi kut"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkrivena je prisutnost korisnika"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string> <string name="install_app" msgid="5066668100199613936">"Instalacija"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prijeđite prstom da biste nastavili"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutarnji zaslon bit će zrcaljen. Prednji zaslon bit će isključen."</string> <string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index fd9d832ceae0..9ac44dfd7972 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nem sikerült beállítani az arcalapú feloldást. Próbálkozzon újra a Beállításokban."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Érintse meg az ujjlenyomat-érzékelőt"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"A folytatáshoz koppintson a Feloldás ikonra"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Az arc nem felismerhető. Használjon ujjlenyomatot."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Az arc nem ismerhető fel"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Használjon ujjlenyomatot"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Nem áll rendelkezésre az Arcalapú feloldás"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth csatlakoztatva."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Töltés • A teljes töltöttségig: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Csúsztasson gyorsan balra a közösségi útmutató elindításához"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"A modulszerkesztő megnyitása"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kész"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Beállítás"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Tárhely"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Tippek"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Azonnali alkalmazások"</string> <string name="instant_apps_title" msgid="8942706782103036910">"A(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazás jelenleg fut"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Az alkalmazás telepítés nélkül lett megnyitva."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Koppintson a kisegítő lehetőségek megnyitásához. A gombot a Beállításokban módosíthatja.\n\n"<annotation id="link">"Beállítások"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"A gombot a szélre áthelyezve ideiglenesen elrejtheti"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Visszavonás"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> gyorsparancs eltávolítva"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# gyorsparancs eltávolítva}other{# gyorsparancs eltávolítva}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Áthelyezés fel és balra"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Felhasználói jelenlét észlelve"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string> <string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Csúsztasson a folytatáshoz"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"A belső kijelző tükrözve lesz. Az elülső kijelző ki lesz kapcsolva."</string> <string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index a9252e2e1eda..0d59017df9e5 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Չհաջողվեց կարգավորել դեմքով ապակողպումը։ Անցեք Կարգավորումներ և նորից փորձեք։"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Հպեք մատնահետքի սկաներին"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Շարունակելու համար սեղմեք ապակողպման պատկերակը"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Դեմքը չի հաջողվում ճանաչել։ Օգտագործեք մատնահետքը։"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Դեմքը չի ճանաչվել"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Օգտագործեք մատնահետք"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Դեմքով ապակողպումն անհասանելի է"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-ը միացված է:"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Լիցքավորում • Մնացել է <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Թերթեք ձախ՝ ուղեցույցը գործարկելու համար"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Բացել վիջեթների խմբագրիչը"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Պատրաստ է"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Կարգավորում"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Տարածք"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Հուշումներ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Ակնթարթային հավելվածներ"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն աշխատում է"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Հավելվածը բացվել է առանց տեղադրման։"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Հատուկ գործառույթները բացելու համար հպեք։ Անհատականացրեք այս կոճակը կարգավորումներում։\n\n"<annotation id="link">"Կարգավորումներ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Կոճակը ժամանակավորապես թաքցնելու համար այն տեղափոխեք էկրանի եզր"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Հետարկել"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"«<xliff:g id="FEATURE_NAME">%s</xliff:g>» դյուրանցումը հեռացվեց"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# դյուրանցում հեռացվեց}one{# դյուրանցում հեռացվեց}other{# դյուրանցում հեռացվեց}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Տեղափոխել վերև՝ ձախ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Հայտնաբերվել է օգտատեր"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string> <string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Սահեցրեք շարունակելու համար"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ներքին էկրանը կհայելապատճենվի։ Առջևի էկրանը կանջատվի։"</string> <string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 8ef809a04b6e..a0b51992e22b 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Tidak dapat menyiapkan buka dengan wajah. Buka Setelan untuk mencoba lagi."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh sensor sidik jari"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tekan ikon buka kunci untuk melanjutkan"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak dapat mengenali wajah. Gunakan sidik jari."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Tidak mengenali wajah"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan sidik jari"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Buka dengan Wajah tidak tersedia"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengisi daya • Penuh dalam waktu <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Geser ke kiri untuk memulai tutorial komunal"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buka editor widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Penyiapan"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Penyimpanan"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Petunjuk"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplikasi Instan"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> sedang berjalan"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikasi dapat dibuka tanpa perlu diinstal."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketuk untuk membuka fitur aksesibilitas. Sesuaikan atau ganti tombol ini di Setelan.\n\n"<annotation id="link">"Lihat setelan"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pindahkan tombol ke tepi agar tersembunyi untuk sementara"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Urungkan"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Pintasan <xliff:g id="FEATURE_NAME">%s</xliff:g> dihapus"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# pintasan dihapus}other{# pintasan dihapus}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pindahkan ke kiri atas"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna terdeteksi"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string> <string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Geser untuk melanjutkan"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Layar dalam akan dicerminkan. Layar depan akan dinonaktifkan."</string> <string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index cef3285e3558..3a0843e4f720 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ekki var hægt að setja upp andlitskenni. Farðu í stillingar og reyndu aftur."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Snertu fingrafaralesarann"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Ýttu á táknið taka úr lás til að halda áfram"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Andlit þekkist ekki. Notaðu fingrafar í staðinn."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Andlit þekkist ekki"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Nota fingrafar í staðinn"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Andlitskenni ekki í boði"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tengt."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Í hleðslu • Full hleðsla eftir <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Strjúktu til vinstri til að hefja samfélagsleiðsögnina"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Opna græjuritilinn"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Lokið"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Uppsetning"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Geymslurými"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Vísbendingar"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Skyndiforrit"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> er í gangi"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Forrit opnað án þess að vera uppsett."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ýttu til að opna aðgengiseiginleika. Sérsníddu eða skiptu hnappinum út í stillingum.\n\n"<annotation id="link">"Skoða stillingar"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Færðu hnappinn að brúninni til að fela hann tímabundið"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Afturkalla"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Flýtileiðin <xliff:g id="FEATURE_NAME">%s</xliff:g> var fjarlægð"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# flýtileið var fjarlægð}one{# flýtileið var fjarlægð}other{# flýtileiðir voru fjarlægðar}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Færa efst til vinstri"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viðvera notanda greindist"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string> <string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Strjúktu til að halda áfram"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Innri skjárinn þinn verður speglaður. Slökkt verður á framskjánum þínum."</string> <string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index c5079fed39b6..8ee96fcd39fd 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Impossibile configurare lo Sblocco con il Volto. Vai alle Impostazioni e riprova."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tocca il sensore di impronte"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Premi l\'icona Sblocca per continuare"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impossibile riconoscere il volto. Usa l\'impronta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Volto non riconosciuto"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usa l\'impronta"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Sblocco con il Volto non disponibile"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth collegato."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • In carica • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> alla ricarica completa"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Scorri a sinistra per iniziare il tutorial della community"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Apri l\'editor del widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fine"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurazione"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Spazio di archiviazione"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Suggerimenti"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"App istantanee"</string> <string name="instant_apps_title" msgid="8942706782103036910">"App <xliff:g id="APP">%1$s</xliff:g> in esecuzione"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App aperta senza essere stata installata."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tocca per aprire funzioni di accessibilità. Personalizza o sostituisci il pulsante in Impostazioni.\n\n"<annotation id="link">"Vedi impostazioni"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sposta il pulsante fino al bordo per nasconderlo temporaneamente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Elimina"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Scorciatoia <xliff:g id="FEATURE_NAME">%s</xliff:g> rimossa"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# scorciatoia rimossa}many{# scorciatoie rimosse}other{# scorciatoie rimosse}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sposta in alto a sinistra"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Viene rilevata la presenza dell\'utente"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string> <string name="install_app" msgid="5066668100199613936">"Installa app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Scorri per continuare"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Verrà eseguito il mirroring del tuo display interno. Il tuo display frontale verrà spento."</string> <string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 486b22f9d222..17236eacd722 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"לא ניתן להגדיר פתיחה ע\"י זיהוי הפנים. צריך לעבור להגדרות כדי לנסות שוב."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"יש לגעת בחיישן טביעות האצבע"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"להמשך יש ללחוץ על סמל ביטול הנעילה"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"לא ניתן לזהות את הפנים. יש להשתמש בטביעת אצבע במקום."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"לא ניתן לזהות את הפנים"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"שימוש בטביעת אצבע במקום זאת"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"אי אפשר לפתוח בזיהוי פנים"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth מחובר."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • בטעינה • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> עד לסיום"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"אפשר להחליק שמאלה כדי להפעיל את המדריך המשותף"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"פתיחה של הכלי לעריכת ווידג\'טים"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"סיום"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"הגדרה"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"אחסון"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"טיפים"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"אפליקציות ללא התקנה"</string> <string name="instant_apps_title" msgid="8942706782103036910">"האפליקציה <xliff:g id="APP">%1$s</xliff:g> פועלת"</string> <string name="instant_apps_message" msgid="6112428971833011754">"האפליקציה נפתחת בלי התקנה."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הלחצן, יש להזיז אותו לקצה"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ביטול"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"קיצור הדרך אל <xliff:g id="FEATURE_NAME">%s</xliff:g> הוסר"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{קיצור הדרך הוסר}one{# קיצורי דרך הוסרו}two{# קיצורי דרך הוסרו}other{# קיצורי דרך הוסרו}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"העברה לפינה השמאלית העליונה"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"נוכחות המשתמש זוהתה"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string> <string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"צריך להחליק כדי להמשיך"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"המסך הפנימי שלך ישוכפל. המסך החיצוני שלך יכובה."</string> <string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index c742f939466e..e193cb14b577 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"顔認証を設定できませんでした。[設定] に移動してもう一度お試しください。"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"指紋認証センサーをタッチ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ロック解除アイコンを押して続行してください"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"顔を認識できません。指紋認証を使用してください。"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"顔を認識できません"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"指紋認証をお使いください"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"顔認証を利用できません"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetoothに接続済み。"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • フル充電まで <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"左にスワイプすると、コミュニティ チュートリアルが開始します"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ウィジェット エディタを開く"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完了"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"セットアップ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ストレージ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ヒント"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> を実行中"</string> <string name="instant_apps_message" msgid="6112428971833011754">"アプリをインストールせずに開きました。"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\n\n"<annotation id="link">"設定を表示"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ボタンを一時的に非表示にするには、端に移動させてください"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"元に戻す"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> のショートカットを削除しました"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# 個のショートカットを削除}other{# 個のショートカットを削除}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"左上に移動"</string> @@ -1207,8 +1225,9 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"会話を始められます"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string> <string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"スワイプして続行"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string> - <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"インナー ディスプレイがミラーリングされます。フロント ディスプレイは OFF になります。"</string> + <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"インナー ディスプレイがミラーリングされます。フロント ディスプレイはオフになります。"</string> <string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string> <string name="dismiss_dialog" msgid="2195508495854675882">"閉じる"</string> <string name="connected_display_icon_desc" msgid="6373560639989971997">"ディスプレイに接続しました"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 9d386efadd02..c841d1c1efbc 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"სახით განბლოკვის დაყენება ვერ მოხერხდა. გადადით პარამეტრებზე და ცადეთ ხელახლა."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"შეეხეთ თითის ანაბეჭდის სენსორს"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"გასაგრძელებლად დააჭირეთ განბლოკვის ხატულას"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"სახის ამოცნობა ვერ ხერხდება. სანაცვლოდ თითის ანაბეჭდი გამოიყენეთ."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"სახის ამოცნობა შეუძლებ."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"გამოიყენეთ თითის ანაბეჭდი"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"სახით განბლოკვა მიუწვდომელია."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth დაკავშირებულია."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • იტენება • სრულ დატენვამდე <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"გადაფურცლეთ მარცხნივ, რათა დაიწყოთ საერთო სახელმძღვანელო"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"გახსენით ვიჯეტის რედაქტორი"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"მზადაა"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"დაყენება"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"მეხსიერება"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"მინიშნებები"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"მყისიერი აპები"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> გაშვებულია"</string> <string name="instant_apps_message" msgid="6112428971833011754">"აპი გაიხსნა ინსტალაციის გარეშე."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"შეეხეთ მარტივი წვდომის ფუნქციების გასახსნელად. მოარგეთ ან შეცვალეთ ეს ღილაკი პარამეტრებში.\n\n"<annotation id="link">"პარამეტრების ნახვა"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"გადაიტანეთ ღილაკი კიდეში, რათა დროებით დამალოთ ის"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"მოქმედების გაუქმება"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> მალსახმობი ამოშლილია"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# მალსახმობი ამოშლილია}other{# მალსახმობი ამოშლილია}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ზევით და მარცხნივ გადატანა"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"აღმოჩენილია მომხმარებლის ყოფნა"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string> <string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"გადაფურცლეთ გასაგრძელებლად"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"თქვენი შიდა ეკრანი აირეკლება. თქვენი წინა ეკრანი გამოირთვება."</string> <string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index d2c60f157f98..f81ad0562433 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Бет тану функциясы реттелмеді. \"Параметрлер\" бөліміне өтіп, әрекетті қайталап көріңіз."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Саусақ ізін оқу сканерін түртіңіз"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Жалғастыру үшін құлыпты ашу белгішесін басыңыз."</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Бет танылмады. Орнына саусақ ізін пайдаланыңыз."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Бет танылмады."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Орнына саусақ ізін пайдаланыңыз."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Бет тану функциясы қолжетімсіз."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth қосылған."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядталып жатыр. • Толуына <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> қалды."</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ортақ оқулықты ашу үшін солға қарай сырғытыңыз."</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет редакторын ашу"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Дайын"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Реттеу"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Жад"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Кеңестер"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> іске қосулы"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Қолданба орнатылмай-ақ ашылды."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Арнайы мүмкіндікті ашу үшін түртіңіз. Түймені параметрден реттеңіз не ауыстырыңыз.\n\n"<annotation id="link">"Параметрді көру"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Түймені уақытша жасыру үшін оны шетке қарай жылжытыңыз."</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Қайтару"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> жылдам пәрмені өшірілді."</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# таңбаша өшірілді.}other{# таңбаша өшірілді.}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жоғарғы сол жаққа жылжыту"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Пайдаланушы анықталды."</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string> <string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Жалғастыру үшін сырғытыңыз."</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ішкі экран көшірмесі көрсетіледі. Алдыңғы экран өшіріледі."</string> <string name="mirror_display" msgid="2515262008898122928">"Көрсету"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index ec81523389b5..09b9e1571ed6 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"មិនអាចរៀបចំការដោះសោតាមទម្រង់មុខបានទេ។ សូមចូលទៅកាន់ការកំណត់ ដើម្បីព្យាយាមម្ដងទៀត។"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ប៉ះឧបករណ៍ចាប់ស្នាមម្រាមដៃ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"សូមចុចរូបដោះសោ ដើម្បីបន្ត"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"មិនអាចសម្គាល់មុខបានទេ។ សូមប្រើស្នាមម្រាមដៃជំនួសវិញ។"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"មិនអាចសម្គាល់មុខបានទេ"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ប្រើស្នាមម្រាមដៃជំនួសវិញ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"មិនអាចប្រើការដោះសោតាមទម្រង់មុខបានទេ"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"បានតភ្ជាប់ប៊្លូធូស។"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • កំពុងសាកថ្ម • ពេញក្នុងរយៈពេល <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"អូសទៅឆ្វេង ដើម្បីចាប់ផ្ដើមមេរៀនសហគមន៍"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"បើកកម្មវិធីកែធាតុក្រាហ្វិក"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុក្រាហ្វិក"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"រួចរាល់"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ការរៀបចំ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ទំហំផ្ទុក"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ការសម្រួល"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"កម្មវិធីប្រើភ្លាមៗ"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> កំពុងដំណើរការ"</string> <string name="instant_apps_message" msgid="6112428971833011754">"កម្មវិធីត្រូវបានបើកដោយមិនចាំបាច់ដំឡើង។"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ចុចដើម្បីបើកមុខងារភាពងាយស្រួល។ ប្ដូរ ឬប្ដូរប៊ូតុងនេះតាមបំណងនៅក្នុងការកំណត់។\n\n"<annotation id="link">"មើលការកំណត់"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ផ្លាស់ទីប៊ូតុងទៅគែម ដើម្បីលាក់វាជាបណ្ដោះអាសន្ន"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ត្រឡប់វិញ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"បានដកផ្លូវកាត់ <xliff:g id="FEATURE_NAME">%s</xliff:g> ចេញ"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{បានដកផ្លូវកាត់ # ចេញ}other{បានដកផ្លូវកាត់ # ចេញ}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងឆ្វេង"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"វត្តមានអ្នកប្រើប្រាស់ត្រូវបានចាប់ដឹង"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string> <string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"សូមអូសដើម្បីបន្ត"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅផ្ទាំងអេក្រង់ខាងក្រៅឬ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"អេក្រង់ខាងក្នុងរបស់អ្នកនឹងត្រូវបានធ្វើសមកាលកម្មទៅវិញទៅមក។ អេក្រង់មុខរបស់អ្នកនឹងត្រូវបានបិទ។"</string> <string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 33f45289ee22..e21715461b82 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -74,7 +74,7 @@ <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="screenshot_saving_work_profile_title" msgid="5332829607308450880">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ಗೆ ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> - <string name="screenshot_saved_title" msgid="8893267638659083153">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಉಳಿಸಲಾಗಿದೆ"</string> + <string name="screenshot_saved_title" msgid="8893267638659083153">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="screenshot_failed_title" msgid="3259148215671936891">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಅನ್ನು ಉಳಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string> <string name="screenshot_failed_external_display_indication" msgid="6555673132061101936">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇ"</string> <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸುವ ಮೊದಲು ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಬೇಕು"</string> @@ -116,7 +116,7 @@ <string name="screenrecord_taps_label" msgid="1595690528298857649">"ಸ್ಪರ್ಶಗಳನ್ನು ಸ್ಕ್ರೀನ್ ಮೇಲೆ ತೋರಿಸಿ"</string> <string name="screenrecord_stop_label" msgid="72699670052087989">"ನಿಲ್ಲಿಸಿ"</string> <string name="screenrecord_share_label" msgid="5025590804030086930">"ಹಂಚಿಕೊಳ್ಳಿ"</string> - <string name="screenrecord_save_title" msgid="1886652605520893850">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಉಳಿಸಲಾಗಿದೆ"</string> + <string name="screenrecord_save_title" msgid="1886652605520893850">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೇವ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="screenrecord_save_text" msgid="3008973099800840163">"ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string> <string name="screenrecord_save_error" msgid="5862648532560118815">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೇವ್ ಮಾಡುವಾಗ ದೋಷ ಎದುರಾಗಿದೆ"</string> <string name="screenrecord_start_error" msgid="2200660692479682368">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸುವಾಗ ದೋಷ ಕಂಡುಬಂದಿದೆ"</string> @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಅನ್ನು ಸೆಟಪ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ಮತ್ತೊಮ್ಮೆ ಪ್ರಯತ್ನಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ಮುಂದುವರಿಯಲು ಅನ್ಲಾಕ್ ಐಕಾನ್ ಅನ್ನು ಒತ್ತಿರಿ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ಮುಖ ಗುರುತಿಸಲಾಗುತ್ತಿಲ್ಲ"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ಬದಲಿಗೆ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಬಳಸಿ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಲಭ್ಯವಿಲ್ಲ"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ಬ್ಲೂಟೂತ್ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ದಲ್ಲಿ ಪೂರ್ಣಗೊಳ್ಳುತ್ತದೆ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ಸಮುದಾಯದ ಟ್ಯುಟೋರಿಯಲ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು ಎಡಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ವಿಜೆಟ್ ಎಡಿಟರ್ ಅನ್ನು ತೆರೆಯಿರಿ"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ಮುಗಿದಿದೆ"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ಸೆಟಪ್"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ಸಂಗ್ರಹಣೆ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ಸುಳಿವುಗಳು"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ರನ್ ಆಗುತ್ತಿದೆ"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ಇನ್ಸ್ಟಾಲ್ ಮಾಡದೆ ಆ್ಯಪ್ ತೆರೆಯಲಾಗಿದೆ."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಈ ಬಟನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ ಅಥವಾ ಬದಲಾಯಿಸಿ.\n\n"<annotation id="link">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಮರೆಮಾಡಲು ಅಂಚಿಗೆ ಬಟನ್ ಸರಿಸಿ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ರದ್ದುಗೊಳಿಸಿ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ಶಾರ್ಟ್ಕಟ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ಶಾರ್ಟ್ಕಟ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ}one{# ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ}other{# ಶಾರ್ಟ್ಕಟ್ಗಳನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ಬಳಕೆದಾರರ ಉಪಸ್ಥಿತಿಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string> <string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ಮುಂದುವರಿಯಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ನಿಮ್ಮ ಒಳಗಿನ ಡಿಸ್ಪ್ಲೇ ಅನ್ನು ಪ್ರತಿಬಿಂಬಿಸಲಾಗುತ್ತದೆ. ನಿಮ್ಮ ಫ್ರಂಟ್ ಡಿಸ್ಪ್ಲೇ ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗುತ್ತದೆ."</string> <string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್ಪ್ಲೇ"</string> diff --git a/packages/SystemUI/res/values-kn/tiles_states_strings.xml b/packages/SystemUI/res/values-kn/tiles_states_strings.xml index 876562dd8584..250eb5adc8de 100644 --- a/packages/SystemUI/res/values-kn/tiles_states_strings.xml +++ b/packages/SystemUI/res/values-kn/tiles_states_strings.xml @@ -34,147 +34,147 @@ <string-array name="tile_states_internet"> <item msgid="5499482407653291407">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="3048856902433862868">"ಆಫ್"</item> - <item msgid="6877982264300789870">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="6877982264300789870">"ಆನ್"</item> </string-array> <string-array name="tile_states_wifi"> <item msgid="8054147400538405410">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4293012229142257455">"ಆಫ್"</item> - <item msgid="6221288736127914861">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="6221288736127914861">"ಆನ್"</item> </string-array> <string-array name="tile_states_cell"> <item msgid="1235899788959500719">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="2074416252859094119">"ಆಫ್"</item> - <item msgid="287997784730044767">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="287997784730044767">"ಆನ್"</item> </string-array> <string-array name="tile_states_battery"> <item msgid="6311253873330062961">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="7838121007534579872">"ಆಫ್"</item> - <item msgid="1578872232501319194">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="1578872232501319194">"ಆನ್"</item> </string-array> <string-array name="tile_states_dnd"> <item msgid="467587075903158357">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="5376619709702103243">"ಆಫ್"</item> - <item msgid="4875147066469902392">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="4875147066469902392">"ಆನ್"</item> </string-array> <string-array name="tile_states_flashlight"> <item msgid="3465257127433353857">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="5044688398303285224">"ಆಫ್"</item> - <item msgid="8527389108867454098">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="8527389108867454098">"ಆನ್"</item> </string-array> <string-array name="tile_states_rotation"> <item msgid="4578491772376121579">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="5776427577477729185">"ಆಫ್"</item> - <item msgid="7105052717007227415">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="7105052717007227415">"ಆನ್"</item> </string-array> <string-array name="tile_states_bt"> <item msgid="5330252067413512277">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="5315121904534729843">"ಆಫ್"</item> - <item msgid="503679232285959074">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="503679232285959074">"ಆನ್"</item> </string-array> <string-array name="tile_states_airplane"> <item msgid="1985366811411407764">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4801037224991420996">"ಆಫ್"</item> - <item msgid="1982293347302546665">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="1982293347302546665">"ಆನ್"</item> </string-array> <string-array name="tile_states_location"> <item msgid="3316542218706374405">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4813655083852587017">"ಆಫ್"</item> - <item msgid="6744077414775180687">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="6744077414775180687">"ಆನ್"</item> </string-array> <string-array name="tile_states_hotspot"> <item msgid="3145597331197351214">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="5715725170633593906">"ಆಫ್"</item> - <item msgid="2075645297847971154">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="2075645297847971154">"ಆನ್"</item> </string-array> <string-array name="tile_states_color_correction"> <item msgid="2840507878437297682">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="1909756493418256167">"ಆಫ್"</item> - <item msgid="4531508423703413340">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="4531508423703413340">"ಆನ್"</item> </string-array> <string-array name="tile_states_inversion"> <item msgid="3638187931191394628">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="9103697205127645916">"ಆಫ್"</item> - <item msgid="8067744885820618230">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="8067744885820618230">"ಆನ್"</item> </string-array> <string-array name="tile_states_saver"> <item msgid="39714521631367660">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="6983679487661600728">"ಆಫ್"</item> - <item msgid="7520663805910678476">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="7520663805910678476">"ಆನ್"</item> </string-array> <string-array name="tile_states_dark"> <item msgid="2762596907080603047">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="400477985171353">"ಆಫ್"</item> - <item msgid="630890598801118771">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="630890598801118771">"ಆನ್"</item> </string-array> <string-array name="tile_states_work"> <item msgid="389523503690414094">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="8045580926543311193">"ಆಫ್"</item> - <item msgid="4913460972266982499">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="4913460972266982499">"ಆನ್"</item> </string-array> <string-array name="tile_states_cast"> <item msgid="6032026038702435350">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="1488620600954313499">"ಆಫ್"</item> - <item msgid="588467578853244035">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="588467578853244035">"ಆನ್"</item> </string-array> <string-array name="tile_states_night"> <item msgid="7857498964264855466">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="2744885441164350155">"ಆಫ್"</item> - <item msgid="151121227514952197">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="151121227514952197">"ಆನ್"</item> </string-array> <string-array name="tile_states_screenrecord"> <item msgid="1085836626613341403">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="8259411607272330225">"ಆಫ್"</item> - <item msgid="578444932039713369">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="578444932039713369">"ಆನ್"</item> </string-array> <string-array name="tile_states_reverse"> <item msgid="3574611556622963971">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="8707481475312432575">"ಆಫ್"</item> - <item msgid="8031106212477483874">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="8031106212477483874">"ಆನ್"</item> </string-array> <string-array name="tile_states_reduce_brightness"> <item msgid="1839836132729571766">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4572245614982283078">"ಆಫ್"</item> - <item msgid="6536448410252185664">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="6536448410252185664">"ಆನ್"</item> </string-array> <string-array name="tile_states_cameratoggle"> <item msgid="6680671247180519913">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4765607635752003190">"ಆಫ್"</item> - <item msgid="1697460731949649844">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="1697460731949649844">"ಆನ್"</item> </string-array> <string-array name="tile_states_mictoggle"> <item msgid="6895831614067195493">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="3296179158646568218">"ಆಫ್"</item> - <item msgid="8998632451221157987">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="8998632451221157987">"ಆನ್"</item> </string-array> <string-array name="tile_states_controls"> <item msgid="8199009425335668294">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="4544919905196727508">"ಆಫ್"</item> - <item msgid="3422023746567004609">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="3422023746567004609">"ಆನ್"</item> </string-array> <string-array name="tile_states_wallet"> <item msgid="4177615438710836341">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="7571394439974244289">"ಆಫ್"</item> - <item msgid="6866424167599381915">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="6866424167599381915">"ಆನ್"</item> </string-array> <string-array name="tile_states_qr_code_scanner"> <item msgid="7435143266149257618">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="3301403109049256043">"ಆಫ್"</item> - <item msgid="8878684975184010135">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="8878684975184010135">"ಆನ್"</item> </string-array> <string-array name="tile_states_alarm"> <item msgid="4936533380177298776">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="2710157085538036590">"ಆಫ್"</item> - <item msgid="7809470840976856149">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="7809470840976856149">"ಆನ್"</item> </string-array> <string-array name="tile_states_onehanded"> <item msgid="8189342855739930015">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="146088982397753810">"ಆಫ್"</item> - <item msgid="460891964396502657">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="460891964396502657">"ಆನ್"</item> </string-array> <string-array name="tile_states_dream"> <item msgid="6184819793571079513">"ಲಭ್ಯವಿಲ್ಲ"</item> <item msgid="8014986104355098744">"ಆಫ್"</item> - <item msgid="5966994759929723339">"ಆನ್ ಮಾಡಿ"</item> + <item msgid="5966994759929723339">"ಆನ್"</item> </string-array> <string-array name="tile_states_font_scaling"> <item msgid="3173069902082305985">"ಲಭ್ಯವಿಲ್ಲ"</item> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 897b266fd65f..940b66dcef2a 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"얼굴 인식 잠금 해제를 설정할 수 없습니다. 설정으로 이동하여 다시 시도해 보세요."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"지문 센서를 터치하세요."</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"계속하려면 잠금 해제 아이콘을 누르세요."</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"얼굴을 인식할 수 없습니다. 대신 지문을 사용하세요."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"얼굴을 인식할 수 없습니다."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"대신 지문을 사용하세요."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"얼굴 인식 잠금 해제를 사용할 수 없습니다."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"블루투스가 연결되었습니다."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 충전 중 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> 후 충전 완료"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"공동 튜토리얼을 시작하려면 왼쪽으로 스와이프하세요"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"위젯 편집기 열기"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"완료"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"설정"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"저장용량"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"힌트"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"인스턴트 앱"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> 실행 중"</string> <string name="instant_apps_message" msgid="6112428971833011754">"설치 없이 앱이 실행되었습니다."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"접근성 기능을 열려면 탭하세요. 설정에서 이 버튼을 맞춤설정하거나 교체할 수 있습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요."</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"실행취소"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> 바로가기 삭제됨"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{바로가기 #개 삭제됨}other{바로가기 #개 삭제됨}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"사용자 정보가 감지되었습니다."</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string> <string name="install_app" msgid="5066668100199613936">"앱 설치"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"계속하려면 스와이프하세요"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"내부 디스플레이가 미러링됩니다. 전면 디스플레이는 꺼집니다."</string> <string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 2f091ec484e0..a6234c3c32d9 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Жүзүнөн таанып ачуу функциясы кошулган жок. Параметрлерге өтүп, кайталап көрүңүз."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Манжа изинин сенсорун басыңыз"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Улантуу үчүн кулпусун ачуу сүрөтчөсүн басыңыз"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Жүз таанылбай жатат. Манжа изин колдонуңуз."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Жүз таанылбай жатат"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Манжа изин колдонуңуз"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\"Жүзүнөн таанып ачуу\" жеткиликсиз"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth байланышта"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Кубатталууда • Толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> калды"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Жалпы үйрөткүчтү иштетүү үчүн солго сүрүңүз"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет түзөткүчтү ачуу"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Бүттү"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Тууралоо"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Сактагыч"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Кеңештер"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Ыкчам ачылуучу колдонмолор"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> иштеп жатат"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Колдонмо орнотулбастан ачылды."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Атайын мүмкүнчүлүктөрдү ачуу үчүн басыңыз. Бул баскычты Параметрлерден өзгөртүңүз.\n\n"<annotation id="link">"Параметрлерди көрүү"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Баскычты убактылуу жашыра туруу үчүн экрандын четине жылдырыңыз"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Кайтаруу"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ыкчам баскычы өчүрүлдү"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ыкчам баскыч өчүрүлдү}other{# ыкчам баскыч өчүрүлдү}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жогорку сол жакка жылдыруу"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Колдонуучу аныкталды"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string> <string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Улантуу үчүн экранды сүрүп коюңуз"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ички экраныңыз башка экранга чыгарылат. Алдыңкы экраныңыз өчүрүлөт."</string> <string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index c0c5d44319b7..87ca72255cbb 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ບໍ່ສາມາດຕັ້ງຄ່າການປົດລັອກດ້ວຍໜ້າໄດ້. ກະລຸນາເຂົ້າໄປການຕັ້ງຄ່າເພື່ອລອງໃໝ່."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມື"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ກົດໄອຄອນປົດລັອກເພື່ອສືບຕໍ່"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ບໍ່ສາມາດຈຳແນກໜ້າໄດ້. ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ກະລຸນາໃຊ້ລາຍນິ້ວມືແທນ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ໃຊ້ການປົດລັອກດ້ວຍໜ້າບໍ່ໄດ້"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ກຳລັງສາກໄຟ • ຈະເຕັມໃນອີກ <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ປັດຊ້າຍເພື່ອເລີ່ມບົດແນະນຳສ່ວນກາງ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ເປີດຕົວແກ້ໄຂວິດເຈັດ"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ແລ້ວໆ"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ຕັ້ງຄ່າ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ບ່ອນເກັບຂໍ້ມູນ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ຄຳໃບ້"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"ອິນສະແຕນແອັບ"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງເຮັດວຽກຢູ່"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ເປີດແອັບໂດຍບໍ່ມີການຕິດຕັ້ງແລ້ວ."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ແຕະເພື່ອເປີດຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ປັບແຕ່ງ ຫຼື ປ່ຽນປຸ່ມນີ້ໃນການຕັ້ງຄ່າ.\n\n"<annotation id="link">"ເບິ່ງການຕັ້ງຄ່າ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ຍ້າຍປຸ່ມໄປໃສ່ຂອບເພື່ອເຊື່ອງມັນຊົ່ວຄາວ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ຍົກເລີກ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"ລຶບທາງລັດ <xliff:g id="FEATURE_NAME">%s</xliff:g> ອອກແລ້ວ"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{ລຶບ # ທາງລັດອອກແລ້ວ}other{ລຶບ # ທາງລັດອອກແລ້ວ}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ຍ້າຍຊ້າຍເທິງ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ກວດພົບຕົວຕົນຜູ້ໃຊ້"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string> <string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ປັດເພື່ອສືບຕໍ່"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ການສະແດງຜົນທາງໃນຂອງທ່ານຈະຖືກສະທ້ອນ. ການສະແດງຜົນທາງໜ້າຂອງທ່ານຈະຖືກປິດໄວ້."</string> <string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 83d2724baff6..eee0f7dddcb2 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nepavyko nustatyti atrakinimo pagal veidą. Eikite į skiltį „Nustatymai“ ir bandykite dar kartą."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Palieskite piršto antspaudo jutiklį"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tęskite paspaudę atrakinimo piktogramą"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Veidas neatpažintas. Naudokite kontrolinį kodą."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Veidas neatpažintas"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Naudoti piršto antspaudą"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Atrakinimo pagal veidą funkcija nepasiekiama"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"„Bluetooth“ prijungtas."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Įkraunama • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> iki visiško įkrovimo"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Perbraukite kairėn, paleistumėte bendruomenės mokomąją medžiagą"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Atidaryti valdiklio redagavimo programą"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Atlikta"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Sąranka"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Saugykla"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Užuominos"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Akimirksniu įkeliamos programos"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Programa „<xliff:g id="APP">%1$s</xliff:g>“ paleista"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Programa atidaryta jos neįdiegus."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Palietę atidarykite pritaikymo neįgaliesiems funkcijas. Tinkinkite arba pakeiskite šį mygtuką nustatymuose.\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Perkelkite mygtuką prie krašto, kad laikinai jį paslėptumėte"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Anuliuoti"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Pašalintas spart. klavišas „<xliff:g id="FEATURE_NAME">%s</xliff:g>“"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Pašalintas # spartusis klavišas}one{Pašalintas # spartusis klavišas}few{Pašalinti # spartieji klavišai}many{Pašalinta # sparčiojo klavišo}other{Pašalinta # sparčiųjų klavišų}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Perkelti į viršų kairėje"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Aptikta naudotojo veikla"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string> <string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Perbraukite, kad galėtumėte tęsti"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Bus bendrinamas vidinio rodinio ekrano vaizdas. Priekinis rodinys bus išjungtas."</string> <string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4bc71c375b74..8631d207c766 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nevarēja iestatīt autorizāciju pēc sejas. Atveriet iestatījumus, lai mēģinātu vēlreiz."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pieskarieties pirksta nospieduma sensoram"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Lai turpinātu, nospiediet atbloķēšanas ikonu."</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nevar atpazīt seju. Lietojiet pirksta nospiedumu."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Nevar atpazīt seju"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Lietot pirksta nospiedumu"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Autorizācija pēc sejas nav pieejama"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth savienojums ir izveidots."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Notiek uzlāde • Laiks līdz pilnai uzlādei: <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Velciet pa kreisi, lai palaistu kopienas pamācību."</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Atvērt logrīku redaktoru"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gatavs"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Iestatīšana"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Krātuve"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Padomi"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Tūlītējās lietotnes"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Lietotne <xliff:g id="APP">%1$s</xliff:g> darbojas"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Lai atvērtu šo lietotni, tā nav jāinstalē."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atveriet pieejamības funkcijas. Pielāgojiet vai aizstājiet šo pogu iestatījumos.\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Lai īslaicīgi paslēptu pogu, pārvietojiet to uz malu"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Atsaukt"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Noņemts īsinājumtaustiņš <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Noņemts # īsinājumtaustiņš}zero{Noņemti # īsinājumtaustiņi}one{Noņemts # īsinājumtaustiņš}other{Noņemti # īsinājumtaustiņi}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pārvietot augšpusē pa kreisi"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Konstatēta lietotāja klātbūtne"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string> <string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Velciet, lai turpinātu"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jūsu iekšējais displejs tiks spoguļots. Jūsu priekšējais displejs tiks izslēgts."</string> <string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 28a2a024f2e6..8f7c2694db62 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не можеше да се постави „Отклучување со лик“. Отворете „Поставки“ за да се обидете повторно."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Допрете го сензорот за отпечатоци"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Притиснете ја иконата за отклучување за да продолжите"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не се препознава ликот. Користете отпечаток."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Не се препознава ликот"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користи отпечаток"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"„Отклучувањето со лик“ е недостапно"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth е поврзан."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Се полни • Полна по <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Повлечете налево за да го започнете заедничкото упатство"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Го отвора уредникот на виџети"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Поставување"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Капацитет"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Совети"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Инстант апликации"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Се извршува <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Апликацијата беше отворена без да се инсталира."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Допрете за функциите за пристапност. Приспособете или заменете го копчево во „Поставки“.\n\n"<annotation id="link">"Прикажи поставки"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете го копчето до работ за да го сокриете привремено"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Врати"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Кратенката за „<xliff:g id="FEATURE_NAME">%s</xliff:g>“ е отстранета"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Отстранета е # кратенка}one{Отстранети се # кратенка}other{Отстранети се # кратенки}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Откриено е присуство на корисник"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Повлечете нагоре за да продолжите"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се преслика на надворешниот екран?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Вашиот внатрешен екран ќе се отслика. Вашиот преден екран ќе се исклучи."</string> <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 057f0b0c09e2..6f8ebc9073bf 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ഫെയ്സ് അൺലോക്ക് സജ്ജീകരിക്കാനായില്ല. വീണ്ടും ശ്രമിക്കാൻ ക്രമീകരണത്തിലേക്ക് പോകുക."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ഫിംഗർപ്രിന്റ് സെൻസർ സ്പർശിക്കുക"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"തുടരാൻ അൺലോക്ക് ഐക്കൺ അമർത്തുക"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"മുഖം തിരിച്ചറിയാനായില്ല. പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"മുഖം തിരിച്ചറിയാനാകുന്നില്ല"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"പകരം ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കൂ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ഫെയ്സ് അൺലോക്ക് ലഭ്യമല്ല"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ബ്ലൂടൂത്ത് കണക്റ്റുചെയ്തു."</string> @@ -413,6 +415,12 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ചാർജ് ചെയ്യുന്നു • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-ൽ പൂർത്തിയാകും"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"കമ്മ്യൂണൽ ട്യൂട്ടോറിയൽ ആരംഭിക്കാൻ ഇടത്തോട്ട് സ്വൈപ്പ് ചെയ്യുക"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"വിജറ്റ് എഡിറ്റർ തുറക്കുക"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"ഇഷ്ടാനുസൃതമാക്കുക"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"ഡിസ്മിസ് ചെയ്യുക"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ഈ സ്പെയ്സിൽ നിങ്ങളുടെ വിജറ്റുകൾ ചേർക്കുക, നീക്കം ചെയ്യുക, പുനഃക്രമീകരിക്കുക"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"കൂടുതൽ വിജറ്റുകൾ ചേർക്കുക"</string> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"പൂർത്തിയായി"</string> @@ -834,6 +842,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"സജ്ജീകരണം"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"സ്റ്റോറേജ്"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"സൂചനകൾ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> റണ് ചെയ്യുന്നു"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ഇൻസ്റ്റാൾ ചെയ്യാതെ ആപ്പ് തുറന്നു."</string> @@ -929,6 +939,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ഉപയോഗസഹായി ഫീച്ചർ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ക്രമീകരണത്തിൽ ഈ ബട്ടൺ ഇഷ്ടാനുസൃതമാക്കാം, മാറ്റാം.\n\n"<annotation id="link">"ക്രമീകരണം കാണൂ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"തൽക്കാലം മറയ്ക്കുന്നതിന് ബട്ടൺ അരുകിലേക്ക് നീക്കുക"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"പഴയപടിയാക്കുക"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> കുറുക്കുവഴി നീക്കം ചെയ്തു"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# കുറുക്കുവഴി നീക്കം ചെയ്തു}other{# കുറുക്കുവഴികൾ നീക്കം ചെയ്തു}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string> @@ -1207,6 +1221,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ഉപയോക്താവിന്റെ സാന്നിധ്യം കണ്ടെത്തി"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string> <string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"തുടരാൻ സ്വൈപ്പ് ചെയ്യുക"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"നിങ്ങളുടെ ഇന്നർ ഡിസ്പ്ലേ മിറർ ചെയ്യും. നിങ്ങളുടെ ഫ്രണ്ട് ഡിസ്പ്ലേ ഓഫാകും."</string> <string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്പ്ലേ"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 933652b17880..cb0eff5a18e1 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Царайгаар түгжээ тайлахыг тохируулж чадсангүй. Дахин оролдохын тулд Тохиргоо руу очно уу."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Хурууны хээ мэдрэгчид хүрэх"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Үргэлжлүүлэхийн тулд түгжээг тайлах дүрс тэмдгийг дарна уу"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Царай таних боломжгүй. Оронд нь хурууны хээ ашигла"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Царайг танихгүй байна"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Оронд нь хурууны хээ ашиглах"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Царайгаар түгжээ тайлах боломжгүй"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth холбогдсон."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Цэнэглэж байна • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>-н дараа дүүрнэ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Нийтийн практик хичээлийг эхлүүлэхийн тулд зүүн тийш шударна уу"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Виджет засварлагчийг нээх"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Болсон"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Тохируулга"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Хадгалах сан"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Заавар"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Шуурхай апп"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g>-г ажиллуулж байна"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Аппыг суулгахгүйгээр нээсэн."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Хандалтын онцлогуудыг нээхийн тулд товшино уу. Энэ товчлуурыг Тохиргоо хэсэгт өөрчилж эсвэл солиорой.\n\n"<annotation id="link">"Тохиргоог харах"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Үүнийг түр нуухын тулд товчлуурыг зах руу зөөнө үү"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Болих"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>-н товчлолыг хассан"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# товчлолыг хассан}other{# товчлолыг хассан}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Зүүн дээш зөөх"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Хэрэглэгч байгааг илрүүлсэн"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string> <string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Үргэлжлүүлэхийн тулд шударна уу"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Таны дотоод дэлгэцийн тусгалыг үүсгэнэ. Таны урд талын дэлгэцийг унтраана."</string> <string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index aad269b2460c..1a19c6b1ab27 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"फेस अनलॉक सेट करता आले नाही. सेटिंग्ज वर जा आणि पुन्हा प्रयत्न करा."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिंट सेन्सरला स्पर्श करा"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"पुढे सुरू ठेवण्यासाठी, अनलॉक करा चा आयकन प्रेस करा"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"चेहरा ओळखू शकत नाही. त्याऐवजी फिंगरप्रिंट वापरा."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"चेहरा ओळखू शकत नाही"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"त्याऐवजी फिंगरप्रिंट वापरा"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फेस अनलॉक उपलब्ध नाही"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लूटूथ कनेक्ट केले."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज होत आहे • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मध्ये पूर्ण होईल"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"सामुदायिक ट्यूटोरियल सुरू करण्यासाठी डावीकडे स्वाइप करा"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट संपादक उघडा"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूर्ण झाले"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"सेटअप"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"स्टोरेज"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"सूचना"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> रन होत आहे"</string> <string name="instant_apps_message" msgid="6112428971833011754">"इंस्टॉल केल्याशिवाय अॅप उघडले."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"अॅक्सेसिबिलिटी वैशिष्ट्ये उघडण्यासाठी, टॅप करा. सेटिंग्जमध्ये हे बटण कस्टमाइझ करा किंवा बदला.\n\n"<annotation id="link">"सेटिंग्ज पहा"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्यामध्ये हलवा"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"पहिल्यासारखे करा"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> शॉर्टकट काढून टाकला"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# शॉर्टकट काढून टाकला}other{# शॉर्टकट काढून टाकले}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"वापरकर्त्याची उपस्थिती डिटेक्ट केली"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string> <string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"सुरू ठेवण्यासाठी स्वाइप करा"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तुमचा अंतर्गत डिस्प्ले मिरर केला जाईल. तुमचा पुढील डिस्प्ले बंद केला जाईल."</string> <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 8287d2bef2ef..3bdb1841ce00 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Tidak dapat menyediakan buka kunci wajah. Akses Tetapan untuk mencuba lagi."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Sentuh penderia cap jari"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tekan ikon buka kunci untuk meneruskan proses"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tidak mengenali wajah. Gunakan cap jari."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Tak dapat mengecam wajah"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gunakan cap jari"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Buka Kunci Wajah tidak tersedia"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth disambungkan."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Mengecas • Penuh dalam masa <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Leret ke kiri untuk memulakan tutorial umum"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buka editor widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Persediaan"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storan"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Pembayang"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Apl Segera"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> sedang berjalan"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Apl dibuka tanpa dipasang."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketik untuk membuka ciri kebolehaksesan. Sesuaikan/gantikan butang ini dalam Tetapan.\n\n"<annotation id="link">"Lihat tetapan"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Gerakkan butang ke tepi untuk disembunyikan buat sementara waktu"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Buat asal"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Pintasan <xliff:g id="FEATURE_NAME">%s</xliff:g> dialih keluar"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# pintasan dialih keluar}other{# pintasan dialih keluar}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Alihkan ke atas sebelah kiri"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna dikesan"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string> <string name="install_app" msgid="5066668100199613936">"Pasang apl"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Leret untuk meneruskan proses"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Paparan dalaman anda akan dicerminkan. Paparan depan anda akan dimatikan."</string> <string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 25afad4991b6..af2d583e6a47 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်းကို စနစ်ထည့်သွင်း၍မရပါ။ ဆက်တင်များသို့သွားပြီး ထပ်စမ်းကြည့်ပါ။"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"လက်ဗွေအာရုံခံကိရိယာကို တို့ပါ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ရှေ့ဆက်ရန် လော့ခ်ဖွင့်သင်္ကေတကို နှိပ်ပါ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"မျက်နှာကို မမှတ်မိပါ။ လက်ဗွေကို အစားထိုးသုံးပါ။"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"မျက်နှာကို မမှတ်မိပါ"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"လက်ဗွေကို အစားထိုးသုံးပါ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း မရနိုင်ပါ"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • အားသွင်းနေသည် • အားပြည့်ရန် <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> လိုသည်"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"အများသုံးရှင်းလင်းပို့ချချက် စတင်ရန် ဘယ်သို့ပွတ်ဆွဲပါ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ဝိဂျက်တည်းဖြတ်စနစ် ဖွင့်ရန်"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ပြီးပြီ"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"စနစ်ထည့်ရန်"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"သိုလှောင်ခန်း"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"အရိပ်အမြွက်များ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> လုပ်ဆောင်နေသည်"</string> <string name="instant_apps_message" msgid="6112428971833011754">"အက်ပ်ကိုမထည့်သွင်းဘဲ ဖွင့်ထားသည်။"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ရန် တို့ပါ။ ဆက်တင်များတွင် ဤခလုတ်ကို စိတ်ကြိုက်ပြင်ပါ (သို့) လဲပါ။\n\n"<annotation id="link">"ဆက်တင်များ ကြည့်ရန်"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ခလုတ်ကို ယာယီဝှက်ရန် အစွန်းသို့ရွှေ့ပါ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"နောက်ပြန်ရန်"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ဖြတ်လမ်းလင့်ခ် ဖယ်ရှားထားသည်"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု ဖယ်ရှားထားသည်}other{ဖြတ်လမ်းလင့်ခ် # ခု ဖယ်ရှားထားသည်}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"အသုံးပြုသူရှိကြောင်း တွေ့ရသည်"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string> <string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ရှေ့ဆက်ရန် ပွတ်ဆွဲပါ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"အတွင်းပြကွက်ကို စကရင်ပွားပါမည်။ ရှေ့မျက်နှာပြင်ပြကွက်ကို ပိတ်မည်။"</string> <string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index d91574353c83..89f58d7d781b 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Kunne ikke konfigurere ansiktslåsen. Gå til innstillingene for å prøve på nytt."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Trykk på fingeravtrykkssensoren"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Trykk på lås opp-ikonet for å fortsette"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet gjenkjennes ikke. Bruk fingeravtrykk."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet gjenkjennes ikke"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bruk fingeravtrykk"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansiktslås er utilgjengelig"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth er tilkoblet."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Lader • Fulladet om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Sveip til venstre for å starte fellesveiledningen"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Åpne redigeringsverktøyet for moduler"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Ferdig"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurering"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hint"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> kjører"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Appen ble åpnet uten at den ble installert."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trykk for å åpne tilgj.funksjoner. Tilpass eller bytt knappen i Innstillinger.\n\n"<annotation id="link">"Se innstillingene"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytt knappen til kanten for å skjule den midlertidig"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Angre"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>-snarveien er fjernet"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# snarvei er fjernet}other{# snarveier er fjernet}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytt til øverst til venstre"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Det er registrert at brukeren er til stede"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string> <string name="install_app" msgid="5066668100199613936">"Installer appen"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Sveip for å fortsette"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den indre skjermen speiles. Den ytre skjermen slås av."</string> <string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 4abb4a4be0d2..51d50443cfc8 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"फेस अनलक सेटअप गर्न सकिएन। फेरि प्रयास गर्न सेटिङमा जानुहोस्।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"जारी राख्न अनलक आइकनमा थिच्नुहोस्"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"अनुहार पहिचान गर्न सकिएन"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फेस अनलक उपलब्ध छैन"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • चार्ज हुँदै छ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> मा फुल चार्ज हुने छ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"कम्युनल ट्युटोरियल सुरु गर्न बायाँतिर स्वाइप गर्नुहोस्"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"विजेट एडिटर खोल्नुहोस्"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूरा भयो"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"सेटअप गर्नुहोस्"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"भण्डारण"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"सङ्केतहरू"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"तात्कालिक एपहरू"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> चलिरहेको छ"</string> <string name="instant_apps_message" msgid="6112428971833011754">"स्थापना नगरिकनै एप खोलियो।"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सर्वसुलभता कायम गर्ने सुविधा खोल्न ट्याप गर्नुहोस्। सेटिङमा गई यो बटन कस्टमाइज गर्नुहोस् वा बदल्नुहोस्।\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"यो बटन केही बेर नदेखिने पार्न किनारातिर सार्नुहोस्"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"अन्डू गर्नुहोस्"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> सर्टकट हटाइएको छ"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# सर्टकट हटाइएको छ}other{# वटा सर्टकट हटाइएका छन्}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सिरानको बायाँतिर सार्नुहोस्"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"प्रयोगकर्ता उपस्थित भएको कुरा पत्ता लागेको छ"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string> <string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी राख्न स्वाइप गर्नुहोस्"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तपाईंको भित्री डिस्प्ले मिरर गरिने छ। तपाईंको अगाडिको डिस्प्ले अफ गरिने छ।"</string> <string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 057673051e23..90551954caee 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Kan ontgrendelen via gezichtsherkenning niet instellen. Ga naar Instellingen om het opnieuw te proberen."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Raak de vingerafdruksensor aan"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Druk op het ontgrendelicoon om door te gaan"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Gezicht niet herkend. Gebruik je vingerafdruk."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Gezicht niet herkend"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Vingerafdruk gebruiken"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ontgrendelen via gezichtsherkenning niet beschikbaar"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-verbinding ingesteld."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Opladen • Vol over <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swipe naar links om de communitytutorial te starten"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"De widget-editor openen"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Instellen"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Opslag"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Hints"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant-apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> actief"</string> <string name="instant_apps_message" msgid="6112428971833011754">"App geopend zonder dat deze is geïnstalleerd."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik voor toegankelijkheidsfuncties. Wijzig of vervang deze knop via Instellingen.\n\n"<annotation id="link">"Naar Instellingen"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Knop naar de rand verplaatsen om deze tijdelijk te verbergen"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Ongedaan maken"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Snelkoppeling voor <xliff:g id="FEATURE_NAME">%s</xliff:g> verwijderd"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# snelkoppeling verwijderd}other{# snelkoppelingen verwijderd}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Naar linksboven verplaatsen"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikersaanwezigheid is waargenomen"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string> <string name="install_app" msgid="5066668100199613936">"App installeren"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe om door te gaan"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Het scherm aan de binnenkant wordt gemirrord. Het scherm aan de voorkant wordt uitgezet."</string> <string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index cb58e64f8eb0..9a31fc0f5109 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ଫେସ ଅନଲକ ସେଟ ଅପ କରାଯାଇପାରିଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରିବା ପାଇଁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ଟିପଚିହ୍ନ ସେନସର୍କୁ ଛୁଅଁନ୍ତୁ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ଜାରି ରଖିବାକୁ ଅନଲକ ଆଇକନ ଦବାନ୍ତୁ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ଫେସ୍ ଚିହ୍ନଟ କରିହେବ ନାହିଁ। ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ।"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ଫେସ ଚିହ୍ନଟ ହୋଇପାରିବ ନାହିଁ"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ଫେସ ଅନଲକ ଉପଲବ୍ଧ ନାହିଁ"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ବ୍ଲୁଟୂଥ୍ ସଂଯୋଗ କରାଯାଇଛି।"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ଚାର୍ଜ ହେଉଛି • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>ରେ ସମ୍ପୂର୍ଣ୍ଣ ହେବ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"କମ୍ୟୁନାଲ ଟ୍ୟୁଟୋରିଆଲ ଆରମ୍ଭ କରିବା ପାଇଁ ବାମକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ୱିଜେଟ ଏଡିଟର ଖୋଲନ୍ତୁ"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ହୋଇଗଲା"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ସେଟଅପ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ଷ୍ଟୋରେଜ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ହିଣ୍ଟ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ଚାଲୁଛି"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ଇନ୍ଷ୍ଟଲ୍ ନହୋଇ ଆପ୍ ଖୋଲିଛି।"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚର ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ। ସେଟିଂସରେ ଏହି ବଟନକୁ କଷ୍ଟମାଇଜ କର କିମ୍ବା ବଦଳାଅ।\n\n"<annotation id="link">"ସେଟିଂସ ଦେଖନ୍ତୁ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଏହାକୁ ଗୋଟିଏ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ପୂର୍ବବତ୍ କରନ୍ତୁ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ସର୍ଟକଟକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{#ଟି ସର୍ଟକଟକୁ କାଢ଼ି ଦିଆଯାଇଛି}other{#ଟି ସର୍ଟକଟକୁ କାଢ଼ି ଦିଆଯାଇଛି}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ୟୁଜରଙ୍କ ଉପସ୍ଥିତି ଚିହ୍ନଟ କରାଯାଇଛି"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string> <string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ଜାରି ରଖିବାକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ଆପଣଙ୍କ ଇନର ଡିସପ୍ଲେକୁ ମିରର କରାଯିବ। ଆପଣଙ୍କ ଫ୍ରଣ୍ଟ ଡିସପ୍ଲେକୁ ବନ୍ଦ କରାଯିବ।"</string> <string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 0340bd192d58..bd71d5f73ebd 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ਫ਼ੇਸ ਅਣਲਾਕ ਦਾ ਸੈੱਟਅੱਪ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਅਣਲਾਕ ਕਰੋ\' ਪ੍ਰਤੀਕ ਨੂੰ ਦਬਾਓ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ਚਿਹਰਾ ਨਹੀਂ ਪਛਾਣ ਸਕਦੇ। ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ।"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ਚਿਹਰੇ ਦੀ ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ਇਸਦੀ ਬਜਾਏ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ਫ਼ੇਸ ਅਣਲਾਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ਕਨੈਕਟ ਕੀਤੀ।"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> ਵਿੱਚ ਪੂਰਾ ਚਾਰਜ ਹੋਵੇਗਾ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ਭਾਈਚਾਰਕ ਟਿਊਟੋਰੀਅਲ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਖੱਬੇ ਪਾਸੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ਵਿਜੇਟ ਸੰਪਾਦਕ ਖੋਲ੍ਹੋ"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ਹੋ ਗਿਆ"</string> @@ -827,13 +839,15 @@ <string name="tuner_right" msgid="8247571132790812149">"ਸੱਜਾ"</string> <string name="tuner_menu" msgid="363690665924769420">"ਮੀਨੂ"</string> <string name="tuner_app" msgid="6949280415826686972">"<xliff:g id="APP">%1$s</xliff:g> ਐਪ"</string> - <string name="notification_channel_alerts" msgid="3385787053375150046">"ਸੁਚੇਤਨਾਵਾਂ"</string> + <string name="notification_channel_alerts" msgid="3385787053375150046">"ਅਲਰਟ"</string> <string name="notification_channel_battery" msgid="9219995638046695106">"ਬੈਟਰੀ"</string> <string name="notification_channel_screenshot" msgid="7665814998932211997">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> <string name="notification_channel_instant" msgid="7556135423486752680">"Instant Apps"</string> <string name="notification_channel_setup" msgid="7660580986090760350">"ਸੈੱਟਅੱਪ ਕਰੋ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ਸਟੋਰੇਜ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ਸੰਕੇਤ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ਚੱਲ ਰਹੀ ਹੈ"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ਸਥਾਪਤ ਕੀਤੇ ਬਿਨਾਂ ਐਪ ਖੋਲ੍ਹੀ ਗਈ।"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਹ ਬਟਨ ਵਿਉਂਤਬੱਧ ਕਰੋ ਜਾਂ ਬਦਲੋ।\n\n"<annotation id="link">"ਸੈਟਿੰਗਾਂ ਦੇਖੋ"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ਬਟਨ ਨੂੰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਲੁਕਾਉਣ ਲਈ ਕਿਨਾਰੇ \'ਤੇ ਲਿਜਾਓ"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"ਅਣਕੀਤਾ ਕਰੋ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਹਟਾਇਆ ਗਿਆ"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਹਟਾਇਆ ਗਿਆ}one{# ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਹਟਾਇਆ ਗਿਆ}other{# ਸ਼ਾਰਟਕੱਟਾਂ ਨੂੰ ਹਟਾਇਆ ਗਿਆ}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ ਦਾ ਪਤਾ ਲਗਾਇਆ ਜਾਂਦਾ ਹੈ"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string> <string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ਤੁਹਾਡੀ ਅੰਦਰੂਨੀ ਡਿਸਪਲੇ ਪ੍ਰਤੀਬਿੰਬਤ ਕੀਤੀ ਜਾਵੇਗੀ। ਤੁਹਾਡੀ ਅਗਲੀ ਡਿਸਪਲੇ ਬੰਦ ਕਰ ਦਿੱਤੀ ਜਾਵੇਗੀ।"</string> <string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index aa24818d6aee..c569f62e448d 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nie udało się skonfigurować rozpoznawania twarzy. Przejdź do ustawień, aby spróbować jeszcze raz."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknij czytnika linii papilarnych"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Aby kontynuować, kliknij ikonę odblokowywania"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nie rozpoznaję twarzy. Użyj odcisku palca."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Nie można rozpoznać twarzy"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Użyj odcisku palca"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Rozpoznawanie twarzy niedostępne"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth połączony."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Ładowanie • Pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Aby uruchomić wspólny samouczek, przeciągnij palcem w lewo"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otwórz edytor widżetów"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotowe"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfiguracja"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć wewnętrzna"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Wskazówki"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplikacje błyskawiczne"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacja została otwarta bez zainstalowania."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Kliknij, aby otworzyć ułatwienia dostępu. Dostosuj lub zmień ten przycisk w Ustawieniach.\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Przesuń przycisk do krawędzi, aby ukryć go tymczasowo"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Cofnij"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> – skrót został usunięty"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# skrót został usunięty}few{# skróty zostały usunięte}many{# skrótów zostało usuniętych}other{# skrótu zostało usunięte}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Przenieś w lewy górny róg"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Wykryto obecność użytkownika"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string> <string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Przesuń, aby kontynuować"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Powstanie odbicie lustrzane Twojego wewnętrznego ekranu. Przedni ekran zostanie wyłączony."</string> <string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index c65c56e8cefd..001872ab6a54 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Não foi possível configurar o Desbloqueio facial. Acesse as Configurações e tente de novo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pressione o ícone de desbloqueio para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O Desbloqueio facial não está disponível"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string> @@ -413,6 +415,12 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Deslize para a esquerda para iniciar o tutorial compartilhado"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Personalizar"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Dispensar"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string> @@ -834,6 +842,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> <string name="instant_apps_message" msgid="6112428971833011754">"O app é aberto sem precisar ser instalado."</string> @@ -929,6 +939,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Desfazer"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Atalho de <xliff:g id="FEATURE_NAME">%s</xliff:g> removido"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# atalho removido}one{# atalho removido}many{# de atalhos removidos}other{# atalhos removidos}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string> @@ -1207,6 +1221,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string> <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 0b9580d2a01c..44317aefcd1f 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Não foi possível configurar o Desbloqueio facial. Aceda às Definições para tentar novamente."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressões digitais."</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Prima o ícone de desbloqueio para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Impos. reconh. rosto. Utilize a impressão digital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Imposs. reconhecer rosto"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Usar impressão digital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Desbloqueio facial indisponível"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ligado."</string> @@ -413,6 +415,12 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • A carregar • Carga completa em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Deslize rapidamente para a esquerda para iniciar o tutorial coletivo"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir editor de widgets"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Personalizar"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Ignorar"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicionar, remover e reordenar widgets neste espaço"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicionar mais widgets"</string> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluir"</string> @@ -834,6 +842,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configuração"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Sugestões"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Apps instantâneas"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> <string name="instant_apps_message" msgid="6112428971833011754">"A app é aberta sem ser instalada."</string> @@ -929,6 +939,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir funcionalidades de acessibilidade. Personal. ou substitua botão em Defin.\n\n"<annotation id="link">"Ver defin."</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a extremidade para o ocultar temporariamente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Anular"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Atalho de <xliff:g id="FEATURE_NAME">%s</xliff:g> removido"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# atalho removido}many{# atalhos removidos}other{# atalhos removidos}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover p/ parte sup. esquerda"</string> @@ -1207,6 +1221,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Quando deteta a presença do utilizador"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string> <string name="install_app" msgid="5066668100199613936">"Instalar app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize rapidamente para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"O seu ecrã interior vai ser espelhado. O seu ecrã frontal vai ser desativado."</string> <string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index c65c56e8cefd..001872ab6a54 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Não foi possível configurar o Desbloqueio facial. Acesse as Configurações e tente de novo."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Toque no sensor de impressão digital"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pressione o ícone de desbloqueio para continuar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Não foi possível reconhecer o rosto Use a impressão digital."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Rosto não reconhecido"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Use a impressão digital"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"O Desbloqueio facial não está disponível"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth conectado."</string> @@ -413,6 +415,12 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Carregando • Conclusão em <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Deslize para a esquerda para iniciar o tutorial compartilhado"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Abrir o editor de widgets"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"Personalizar"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"Dispensar"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string> @@ -834,6 +842,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurar"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Armazenamento"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Dicas"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> em execução"</string> <string name="instant_apps_message" msgid="6112428971833011754">"O app é aberto sem precisar ser instalado."</string> @@ -929,6 +939,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Desfazer"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Atalho de <xliff:g id="FEATURE_NAME">%s</xliff:g> removido"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# atalho removido}one{# atalho removido}many{# de atalhos removidos}other{# atalhos removidos}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string> @@ -1207,6 +1221,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string> <string name="install_app" msgid="5066668100199613936">"Instalar o app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string> <string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index b2fdef3bcde6..ab31599d0d4c 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Nu s-a putut configura deblocarea facială. Accesează Setările pentru a încerca din nou."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Atinge senzorul de amprente"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Apasă pe pictograma de deblocare pentru a continua"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosește amprenta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Chip nerecunoscut"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Folosește amprenta"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Deblocarea facială nu este disponibilă"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Conectat prin Bluetooth."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Se încarcă • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> până la încărcarea completă"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Glisează spre stânga pentru a începe tutorialul pentru comunitate"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Deschide editorul de widgeturi"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gata"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Configurarea"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Stocare"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Indicii"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplicații instantanee"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> rulează"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplicația a fost deschisă fără a fi instalată."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atinge ca să deschizi funcțiile de accesibilitate. Personalizează sau înlocuiește butonul în setări.\n\n"<annotation id="link">"Vezi setările"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mută butonul spre margine pentru a-l ascunde temporar"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Anulează"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Comandă rapidă <xliff:g id="FEATURE_NAME">%s</xliff:g> eliminată"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# comandă rapidă eliminată}few{# comenzi rapide eliminate}other{# de comenzi rapide eliminate}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mută în stânga sus"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"S-a detectat prezența utilizatorului"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string> <string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Glisează pentru a continua"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ecranul interior va fi oglindit. Ecranul frontal va fi dezactivat."</string> <string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index ff4bd45745c9..b6ff0dbdc710 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не удалось настроить фейсконтроль. Перейдите в настройки и повторите попытку."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Прикоснитесь к сканеру отпечатков пальцев."</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Нажмите на значок разблокировки."</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Не удалось распознать лицо. Используйте отпечаток."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Лицо не распознано."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Используйте отпечаток."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейсконтроль недоступен"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth-соединение установлено."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Зарядка • Осталось <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Чтобы ознакомиться с руководством, проведите по экрану влево"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Открыть редактор виджетов"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Настройка"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Хранилище"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Подсказки"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Приложения с мгновенным запуском"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> уже здесь!"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Приложение готово к работе, установка не требуется."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Нажмите, чтобы открыть спец. возможности. Настройте или замените эту кнопку в настройках.\n\n"<annotation id="link">"Настройки"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Чтобы временно скрыть кнопку, переместите ее к краю экрана"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Отменить"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>: сочетание клавиш удалено."</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# сочетание клавиш удалено}one{# сочетание клавиш удалено}few{# сочетания клавиш удалено}many{# сочетаний клавиш удалено}other{# сочетания клавиш удалено}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перенести в левый верхний угол"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Обнаружен пользователь"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string> <string name="install_app" msgid="5066668100199613936">"Установить приложение"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Проведите по экрану, чтобы продолжить."</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Для внутреннего экрана включится дублирование. Передний экран будет отключен."</string> <string name="mirror_display" msgid="2515262008898122928">"Дублировать"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 4b4d08bd8189..5c9faab8680e 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"මුහුණෙන් අගුළු හැරීම පිහිටුවිය නොහැකි විය. නැවත උත්සාහ කිරීමට සැකසීම් වෙත යන්න."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"ඉදිරියට යාමට අගුළු ඇරීමේ නිරූපකය ඔබන්න"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"මුහුණ හැඳිනිය නොහැක. ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත ක."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"මුහුණ හඳුනා ගත නොහැක"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ඒ වෙනුවට ඇඟිලි සලකුණ භාවිත කරන්න"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"මුහුණෙන් අගුළු ඇරීම නැත"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"බ්ලූටූත් සම්බන්ධිතයි."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ආරෝපණය වෙමින් • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>කින් සම්පූර්ණ වේ"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"පොදු නිබන්ධනය ආරම්භ කිරීමට වමට ස්වයිප් කරන්න"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"විජට් සංස්කාරකය විවෘත කරන්න"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"නිමයි"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"පිහිටුවීම"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"ගබඩාව"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"ඉඟි"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"ක්ෂණික යෙදුම්"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ධාවනය වෙමින්"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ස්ථාපනය නොකර යෙදුම විවෘත කර ඇත."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ප්රවේශ්යතා විශේෂාංග විවෘත කිරීමට තට්ටු කරන්න. සැකසීම් තුළ මෙම බොත්තම අභිරුචිකරණය හෝ ප්රතිස්ථාපනය කරන්න.\n\n"<annotation id="link">"සැකසීම් බලන්න"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"එය තාවකාලිකව සැඟවීමට බොත්තම දාරයට ගෙන යන්න"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"අස් කරන්න"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> කෙටිමඟ ඉවත් කළා"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# කෙටිමඟක් ඉවත් කළා}one{කෙටිමං #ක් ඉවත් කළා}other{කෙටිමං #ක් ඉවත් කළා}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ඉහළ වමට ගෙන යන්න"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"පරිශීලක රූපාකාරය අනාවරණය වේ"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string> <string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ඉදිරියට යාමට ස්වයිප් කරන්න"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ඔබේ අභ්යන්තර සංදර්ශකය පිළිබිඹු වනු ඇත. ඔබේ ඉදිරිපස සංදර්ශකය ක්රියාවිරහිත වනු ඇත."</string> <string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 9e9507e92eb9..ae567c7804d9 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Odomknutie tvárou sa nepodarilo nastaviť. Prejdite do Nastavení a skúste to znova."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotknite sa senzora odtlačkov prstov"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pokračujte stlačením ikony odomknutia"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Tvár sa nedá rozpoznať. Použite odtlačok prsta."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Tvár sa nedá rozpoznať"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Používať radšej odtlačok"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odomknutie tvárou nie je k dispozícii"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth pripojené."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nabíja sa • Do úplného nabitia zostáva <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Potiahnutím doľava spustite komunitný návod"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Otvoriť editor miniaplikácií"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavenie"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Úložisko"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Tipy"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Okamžité aplikácie"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Aplikácia <xliff:g id="APP">%1$s</xliff:g> je spustená"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikácia bola otvorená bez inštalácie."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Funkcie dostupnosti otvoríte klepnutím. Tlačidlo prispôsobte alebo nahraďte v Nastav.\n\n"<annotation id="link">"Zobraz. nast."</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ak chcete tlačidlo dočasne skryť, presuňte ho k okraju"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Späť"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Bola odstránená skratka <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Bola odstránená # skratka}few{Boli odstránené # skratky}many{# shortcuts removed}other{Bolo odstránených # skratiek}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Presunúť doľava nahor"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Bola rozpoznaná prítomnosť používateľa"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string> <string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte potiahnutím"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnútorná obrazovka bude zrkadlená. Predná obrazovka bude vypnutá."</string> <string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index cba54167fe86..c2f26936febc 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Odklepanja z obrazom ni bilo mogoče nastaviti. Odprite nastavitve in poskusite znova."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Dotaknite se tipala prstnih odtisov"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Za nadaljevanje pritisnite ikono za odklepanje"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Obraza ni mogoče prepoznati. Uporabite prstni odtis."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Obraz ni bil prepoznan."</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Uporabite prstni odtis."</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Odklepanje z obrazom ni na voljo."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Povezava Bluetooth vzpostavljena."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Polnjenje • Napolnjeno čez <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Povlecite levo, da zaženete vadnico za skupnost"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Odpiranje urejevalnika pripomočkov"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Končano"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Nastavitev"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Shramba"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Namigi"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Nenamestljive aplikacije"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> se izvaja"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacija je odprta brez namestitve."</string> @@ -897,10 +911,10 @@ <string name="accessibility_control_move_down" msgid="5390922476900974512">"Premakni navzdol"</string> <string name="accessibility_control_move_left" msgid="8156206978511401995">"Premakni levo"</string> <string name="accessibility_control_move_right" msgid="8926821093629582888">"Premakni desno"</string> - <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povečanje širine povečevalnika"</string> - <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Zmanjšanje širine povečevalnika"</string> - <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povečanje višine povečevalnika"</string> - <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Zmanjšanje višine povečevalnika"</string> + <string name="accessibility_control_increase_window_width" msgid="6992249470832493283">"Povečanje širine lupe"</string> + <string name="accessibility_control_decrease_window_width" msgid="5740401560105929681">"Zmanjšanje širine lupe"</string> + <string name="accessibility_control_increase_window_height" msgid="2200966116612324260">"Povečanje višine lupe"</string> + <string name="accessibility_control_decrease_window_height" msgid="2054479949445332761">"Zmanjšanje višine lupe"</string> <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Stikalo za povečavo"</string> <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Povečanje celotnega zaslona"</string> <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Povečava dela zaslona"</string> @@ -917,7 +931,7 @@ <string name="accessibility_magnification_right_handle" msgid="9055988237319397605">"Ročica desno"</string> <string name="accessibility_magnification_bottom_handle" msgid="6531646968813821258">"Ročica spodaj"</string> <string name="accessibility_magnification_settings_panel_description" msgid="8174187340747846953">"Nastavitve povečave"</string> - <string name="accessibility_magnifier_size" msgid="3038755600030422334">"Velikost povečevalnika"</string> + <string name="accessibility_magnifier_size" msgid="3038755600030422334">"Velikost lupe"</string> <string name="accessibility_magnification_zoom" msgid="4222088982642063979">"Povečava/pomanjšava"</string> <string name="accessibility_magnification_medium" msgid="6994632616884562625">"Srednja"</string> <string name="accessibility_magnification_small" msgid="8144502090651099970">"Majhna"</string> @@ -925,10 +939,14 @@ <string name="accessibility_magnification_fullscreen" msgid="5043514702759201964">"Celozaslonski način"</string> <string name="accessibility_magnification_done" msgid="263349129937348512">"Končano"</string> <string name="accessibility_magnifier_edit" msgid="1522877239671820636">"Uredi"</string> - <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavitve okna povečevalnika"</string> + <string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavitve okna lupe"</string> <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dotaknite se za funkcije dostopnosti. Ta gumb lahko prilagodite ali zamenjate v nastavitvah.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Če želite gumb začasno skriti, ga premaknite ob rob."</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Razveljavi"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Odstranjena bližnjica za fun. <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Odstranjena # bližnjica}one{Odstranjena # bližnjica}two{Odstranjeni # bližnjici}few{Odstranjene # bližnjice}other{Odstranjenih # bližnjic}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premakni zgoraj levo"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Zaznana je prisotnost uporabnika"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string> <string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Povlecite za nadaljevanje"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti na zunanji zaslon?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Notranji zaslon bo zrcaljen. Sprednji zaslon bo izklopljen."</string> <string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index b35668f45d37..4443954fb2d1 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Shkyçja me fytyrë nuk mund të konfigurohej. Shko te \"Cilësimet\" për të provuar përsëri."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Prek sensorin e gjurmës së gishtit"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Shtyp ikonën e shkyçjes për të vazhduar"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Nuk mund ta dallojë fytyrën. Përdor më mirë gjurmën e gishtit."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Fytyra nuk mund të njihet"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Përdor më mirë gjurmën e gishtit"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"\"Shkyçja me fytyrë\" nuk ofrohet"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Pajisja është lidhur me \"bluetooth\"."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Po karikohet • Plot për <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Rrëshqit shpejt majtas për të filluar udhëzuesin e përbashkët"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Hap modifikuesin e miniaplikacionit"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"U krye"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurimi"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Hapësira ruajtëse"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Sugjerimet"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Aplikacionet e çastit"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Po ekzekutohet <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Aplikacioni u hap pa u instaluar."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trokit dhe hap veçoritë e qasshmërisë. Modifiko ose ndërro butonin te \"Cilësimet\".\n\n"<annotation id="link">"Shih cilësimet"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Zhvendose butonin në skaj për ta fshehur përkohësisht"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Zhbëj"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Shkurtorja për \"<xliff:g id="FEATURE_NAME">%s</xliff:g>\" u hoq"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shkurtore u hoq}other{# shkurtore u hoqën}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Zhvendos lart majtas"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Është zbuluar prania e përdoruesit"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string> <string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Rrëshqit shpejt për të vazhduar"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ekrani i brendshëm do të pasqyrohet. Ekrani i parmë do të çaktivizohet."</string> <string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 1d45fbd5267c..ac1d7bfbf512 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Подешавање откључавања лицем није успело. Идите у Подешавања да бисте пробали поново."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Додирните сензор за отисак прста"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Притисните икону откључавања за наставак"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Лице није препознато. Користите отисак прста."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Лице није препознато"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Користите отисак прста"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Откључавање лицем није доступно"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth је прикључен."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Пуни се • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до краја пуњења"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Превуците улево да бисте започели заједнички водич"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Отвори уређивач виџета"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Подешавање"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Меморијски простор"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Савети"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Инстант апликације"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Апликација <xliff:g id="APP">%1$s</xliff:g> је покренута"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Апликација се отворила без инсталирања."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Додирните за функције приступачности. Прилагодите или замените ово дугме у Подешавањима.\n\n"<annotation id="link">"Подешавања"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Померите дугме до ивице да бисте га привремено сакрили"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Опозови"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Пречица функције <xliff:g id="FEATURE_NAME">%s</xliff:g> је уклоњена"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# пречица је уклоњена}one{# пречица је уклоњена}few{# пречице су уклоњене}other{# пречица је уклоњено}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Присуство корисника може да се открије"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string> <string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Превуците да бисте наставили"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Унутрашњи екран ће се пресликати. Предњи екран ће се искључити."</string> <string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 0d6272f532b1..f8dbbc590630 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Det gick inte att konfigurera ansiktslåset. Öppna inställningarna och försök igen."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Tryck på fingeravtryckssensorn"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Tryck på ikonen lås upp för att fortsätta"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ansiktet kändes inte igen. Använd fingeravtryck."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Ansiktet kändes inte igen"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Använd fingeravtryck"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ansiktslås är otillgängligt"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ansluten."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Laddas • Fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Svep åt vänster för att börja med gruppguiden"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Öppna widgetredigeraren"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klar"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Konfigurering"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Lagring"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Tips"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Snabbappar"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> körs"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Appen öppnades utan installation."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryck för att öppna tillgänglighetsfunktioner. Anpassa/ersätt knappen i Inställningar.\n\n"<annotation id="link">"Inställningar"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytta knappen till kanten för att dölja den tillfälligt"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Ångra"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Genväg till <xliff:g id="FEATURE_NAME">%s</xliff:g> har tagits bort"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# genväg har tagits bort}other{# genvägar har tagits bort}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytta högst upp till vänster"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Användarnärvaro har upptäckts"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string> <string name="install_app" msgid="5066668100199613936">"Installera appen"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Svep för att fortsätta"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den inre skärmen speglas. Den främre skärmen stängs av."</string> <string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 1bd2ed7aa30d..dbc2eea39aad 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Imeshindwa kuweka mipangilio ya kufungua kwa uso. Nenda kwenye Mipangilio ili ujaribu tena."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Gusa kitambua alama ya kidole"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Bonyeza aikoni ya kufungua ili uendelee"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Imeshindwa kutambua uso. Tumia alama ya kidole."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Imeshindwa kutambua uso"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Badala yake, tumia alama ya kidole"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Kipengele cha Kufungua kwa Uso hakipatikani"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth imeunganishwa."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Inachaji • Itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Telezesha kidole kushoto ili uanze mafunzo ya pamoja"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Fungua kihariri cha wijeti"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Nimemaliza"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Weka mipangilio"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Hifadhi"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Vidokezo"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Programu Zinazofunguka Papo Hapo"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Programu ya <xliff:g id="APP">%1$s</xliff:g> inatumika"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Programu inafunguka bila kusakinishwa."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Gusa ili ufungue vipengele vya ufikivu. Weka mapendeleo au ubadilishe kitufe katika Mipangilio.\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sogeza kitufe kwenye ukingo ili ukifiche kwa muda"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Tendua"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Njia ya mkato ya <xliff:g id="FEATURE_NAME">%s</xliff:g> imeondolewa"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Njia # ya mkato imeondolewa}other{Njia # za mkato zimeondolewa}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sogeza juu kushoto"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Imetambua uwepo wa mtumiaji"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string> <string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Telezesha kidole ili uendelee"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Mwonekano wa ndani wa kifaa chako utaakisiwa. Mwonekano wa mbele wa kifaa chako utazimwa."</string> <string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 0cd076f77d3e..d70992e2d09d 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"\'முகம் காட்டித் திறத்தல்\' அம்சத்தை அமைக்க முடியவில்லை. அமைப்புகளுக்குச் சென்று மீண்டும் முயலவும்."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"கைரேகை சென்சாரைத் தொடவும்"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"தொடர, அன்லாக் ஐகானை அழுத்துங்கள்"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"முகத்தை அடையாளம் காண முடியவில்லை. கைரேகையைப் பயன்படுத்தவும்."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"முகத்தை கண்டறிய இயலவில்லை"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"கைரேகையை உபயோகிக்கவும்"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"முகம் காட்டித் திறத்தல் அம்சம் கிடைக்கவில்லை"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"புளூடூத் இணைக்கப்பட்டது."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • சார்ஜாகிறது • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> இல் முழுவதும் சார்ஜாகும்"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"சமூகப் பயிற்சியைத் தொடங்க இடதுபுறம் ஸ்வைப் செய்யுங்கள்"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"விட்ஜெட் எடிட்டரைத் திறக்கும்"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"முடிந்தது"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"அமைவு"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"சேமிப்பிடம்"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"குறிப்புகள்"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> இயங்குகிறது"</string> <string name="instant_apps_message" msgid="6112428971833011754">"நிறுவ வேண்டிய தேவையில்லாமல் ஆப்ஸ் திறக்கப்பட்டது."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"அணுகல்தன்மை அம்சத்தை திறக்க தட்டவும். அமைப்பில் பட்டனை பிரத்தியேகமாக்கலாம்/மாற்றலாம்.\n\n"<annotation id="link">"அமைப்பில் காண்க"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"பட்டனைத் தற்காலிகமாக மறைக்க ஓரத்திற்கு நகர்த்தும்"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"செயல்தவிர்"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ஷார்ட்கட் அகற்றப்பட்டது"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ஷார்ட்கட் அகற்றப்பட்டது}other{# ஷார்ட்கட்கள் அகற்றப்பட்டன}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"மேலே இடதுபுறத்திற்கு நகர்த்து"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"பயனர் கண்டறியப்பட்டுள்ளார்"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string> <string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ஸ்வைப் செய்து தொடரலாம்"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"உங்கள் உட்புற டிஸ்பிளே பிரதிபலிக்கப்படும். உங்கள் முன்புற டிஸ்பிளே முடக்கப்படும்."</string> <string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index 6a59812d39b4..c87762e5e6b2 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ఫేస్ అన్లాక్ను సెటప్ చేయడం సాధ్యపడలేదు. సెట్టింగ్లకు వెళ్లి, ఆపై మళ్లీ ట్రై చేయండి."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"వేలిముద్ర సెన్సార్ను తాకండి"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"కొనసాగించడానికి అన్లాక్ చిహ్నాన్ని నొక్కండి"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ముఖం గుర్తించలేము. బదులుగా వేలిముద్ర ఉపయోగించండి."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ముఖం గుర్తించడం కుదరలేదు"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"బదులుగా వేలిముద్రను ఉపయోగించండి"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"ఫేస్ అన్లాక్ అందుబాటులో లేదు"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string> @@ -413,6 +415,12 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • ఛార్జ్ అవుతోంది • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"కమ్యూనల్ ట్యుటోరియల్ను ప్రారంభించడానికి ఎడమ వైపునకు స్వైప్ చేయండి"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"విడ్జెట్ ఎడిటర్ను తెరవండి"</string> + <string name="cta_tile_button_to_open_widget_editor" msgid="3871562362382963878">"అనుకూలంగా మార్చండి"</string> + <string name="cta_tile_button_to_dismiss" msgid="3377597875997861754">"విస్మరించండి"</string> + <string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ఈ స్పేస్లో మీ విడ్జెట్లను జోడించండి, తీసివేయండి, క్రమపద్ధతిలో అమర్చండి"</string> + <string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"మరిన్ని విడ్జెట్లను జోడించండి"</string> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్ను జోడించండి"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"పూర్తయింది"</string> @@ -834,6 +842,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"సెటప్ చేయండి"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"స్టోరేజ్"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"సూచనలు"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"ఇన్స్టంట్ యాప్లు"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> అమలవుతోంది"</string> <string name="instant_apps_message" msgid="6112428971833011754">"ఇన్స్టాల్ చేయకుండా యాప్ తెరవబడింది."</string> @@ -929,6 +939,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్లలో ఈ బటన్ను అనుకూలంగా మార్చండి లేదా రీప్లేస్ చేయండి.\n\n"<annotation id="link">"వీక్షణ సెట్టింగ్లు"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్ను చివరకు తరలించండి"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"చర్య రద్దు చేయండి"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> షార్ట్కట్ తీసివేయబడింది"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# షార్ట్కట్ తీసివేయబడింది}other{# షార్ట్కట్లు తీసివేయబడ్డాయి}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ఎగువ ఎడమ వైపునకు తరలించు"</string> @@ -1207,6 +1221,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"యూజర్ ఉనికి గుర్తించబడింది"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string> <string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"కొనసాగించడానికి స్వైప్ చేయండి"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ఎక్స్టర్నల్ డిస్ప్లేకి మిర్రర్ చేయాలా?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"మీ లోపలి డిస్ప్లే మిర్రర్ చేయబడుతుంది. మీ ముందు వైపు డిస్ప్లే ఆఫ్ చేయబడుతుంది."</string> <string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్ప్లే"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index dc4c6cf36b7a..ab50427a7f6e 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"ตั้งค่าการปลดล็อกด้วยใบหน้าไม่ได้ ไปที่การตั้งค่าเพื่อลองอีกครั้ง"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"แตะเซ็นเซอร์ลายนิ้วมือ"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"กดไอคอนปลดล็อกเพื่อดำเนินการต่อ"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"ไม่รู้จักใบหน้า ใช้ลายนิ้วมือแทน"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"ไม่รู้จักใบหน้า"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"ใช้ลายนิ้วมือแทน"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"การปลดล็อกด้วยใบหน้าไม่พร้อมใช้งาน"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"เชื่อมต่อบลูทูธแล้ว"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • กำลังชาร์จ • จะเต็มในอีก <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"ปัดไปทางซ้ายเพื่อเริ่มบทแนะนำส่วนกลาง"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"เปิดเครื่องมือแก้ไขวิดเจ็ต"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"เสร็จสิ้น"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"ตั้งค่า"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"พื้นที่เก็บข้อมูล"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"คำแนะนำ"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant App"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ทำงานอยู่"</string> <string name="instant_apps_message" msgid="6112428971833011754">"เปิดแอปได้โดยไม่ต้องติดตั้ง"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"แตะเพื่อเปิดฟีเจอร์การช่วยเหลือพิเศษ ปรับแต่งหรือแทนที่ปุ่มนี้ในการตั้งค่า\n\n"<annotation id="link">"ดูการตั้งค่า"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ย้ายปุ่มไปที่ขอบเพื่อซ่อนชั่วคราว"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"เลิกทำ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"นำทางลัด <xliff:g id="FEATURE_NAME">%s</xliff:g> ออกแล้ว"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{นำทางลัด # รายการออกแล้ว}other{นำทางลัด # รายการออกแล้ว}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ย้ายไปด้านซ้ายบน"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"ตรวจพบการแสดงข้อมูลของผู้ใช้"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string> <string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ปัดเพื่อทำต่อ"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ระบบจะมิเรอร์หน้าจอด้านใน และจะปิดหน้าจอด้านหน้า"</string> <string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index c09ac9748b6f..dcd687a15499 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Hindi na-set up ang pag-unlock gamit ang mukha. Pumunta sa Mga Setting para subukan ulit."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Pindutin ang fingerprint sensor"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Pindutin ang icon ng pag-unlock para magpatuloy"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Hindi makilala ang mukha. Gumamit ng fingerprint."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Hindi makilala ang mukha"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Gumamit ng fingerprint"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Hindi available ang Pag-unlock Gamit ang Mukha"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Nakakonekta ang Bluetooth."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Nagcha-charge • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> na lang para mapuno"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Mag-swipe pakaliwa para simulan ang communal na tutorial"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Buksan ang editor ng widget"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tapos na"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Setup"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Storage"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Mga Hint"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Instant Apps"</string> <string name="instant_apps_title" msgid="8942706782103036910">"Tumatakbo ang <xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Nabuksan ang app nang hindi ini-install."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"I-tap, buksan mga feature ng accessibility. I-customize o palitan button sa Mga Setting.\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ilipat ang button sa gilid para pansamantala itong itago"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"I-undo"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> shortcut ang naalis"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# shortcut ang naalis}one{# shortcut ang naalis}other{# na shortcut ang naalis}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Ilipat sa kaliwa sa itaas"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Na-detect ang presensya ng user"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string> <string name="install_app" msgid="5066668100199613936">"I-install ang app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Mag-swipe para magpatuloy"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Imi-mirror ang inner display mo. Io-off ang iyong front display."</string> <string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index ee1909b28098..f04340433697 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Yüz tanıma kilidi kurulamadı. Tekrar denemek için Ayarlar\'a gidin."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Parmak izi sensörüne dokunun"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Devam etmek için kilit açma simgesine basın"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Yüz tanınamadı. Bunun yerine parmak izi kullanın."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Yüz tanınamadı"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Bunun yerine parmak izi kullanın"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Yüz Tanıma Kilidi kullanılamıyor"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth bağlandı."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Şarj oluyor • Dolmasına <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> kaldı"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Ortak eğitimi başlatmak için sola kaydırın"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Widget düzenleyiciyi açın"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Bitti"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Kurulum"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Depolama alanı"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"İpuçları"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Hazır Uygulamalar"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> çalışıyor"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Uygulama yüklenmeden açıldı."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erişilebilirlik özelliklerini açmak için dokunun. Bu düğmeyi Ayarlar\'dan özelleştirin veya değiştirin.\n\n"<annotation id="link">"Ayarları göster"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düğmeyi geçici olarak gizlemek için kenara taşıyın"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Geri al"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> kısayol kaldırıldı"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# kısayol kaldırıldı}other{# kısayol kaldırıldı}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sol üste taşı"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Kullanıcı varlığı algılandı"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string> <string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Devam etmek için kaydırın"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç ekranınız yansıtılacak. Ön ekranınız kapatılacak."</string> <string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 04a97bcecb80..fce90e5dc897 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Не вдалося налаштувати фейс-контроль. Перейдіть у налаштування, щоб повторити спробу."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Торкніться сканера відбитків пальців"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Щоб продовжити, натисніть значок розблокування"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Обличчя не розпізнано. Скористайтеся відбитком пальця."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Обличчя не розпізнано"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Скористайтеся відбитком"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Фейс-контроль недоступний"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth під’єднано."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Заряджання • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> до повного заряду"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Проведіть пальцем уліво, щоб відкрити спільний навчальний посібник"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Відкрити редактор віджетів"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Налаштування"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Пам’ять"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Поради"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Додатки з миттєвим запуском"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> працює"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Додаток відкрито без встановлення."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Торкніться, щоб відкрити функції доступності. Змінити або замінити цю кнопку можна в Налаштуваннях.\n\n"<annotation id="link">"Налаштування"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Щоб тимчасово сховати кнопку, перемістіть її на край екрана"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Відмінити"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g>: швидкий запуск вилучено"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ярлик вилучено}one{# ярлик вилучено}few{# ярлики вилучено}many{# ярликів вилучено}other{# ярлика вилучено}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перемістити ліворуч угору"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Виявлено присутність користувача"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string> <string name="install_app" msgid="5066668100199613936">"Установити додаток"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Щоб продовжити, проведіть пальцем по екрану"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ваш внутрішній екран буде продубльовано. Передній екран буде вимкнено."</string> <string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index fd984b9c4ae7..1ae2118d1e4d 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"فیس اَن لاک کو سیٹ اپ نہیں کیا جا سکا۔ دوبارہ کوشش کرنے کیلئے ترتیبات پر جائیں۔"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"فنگر پرنٹ سینسر پر ٹچ کریں"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"جاری رکھنے کیلئے غیر مقفل کرنے کا آئیکن دبائیں"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"چہرے کی شناخت نہیں ہو سکی۔ اس کے بجائے فنگر پرنٹ استعمال کریں۔"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"چہرے کی پہچان نہیں ہو سکی"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"اس کے بجائے فنگر پرنٹ استعمال کریں"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"فیس اَنلاک غیر دستیاب ہے"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"بلوٹوتھ مربوط ہے۔"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • چارج ہو رہا ہے • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> میں مکمل"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"کمیونل ٹیوٹوریل شروع کرنے کے لیے بائیں سوائپ کریں"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"ویجیٹ ایڈیٹر کو کھولیں"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ہو گیا"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"سیٹ اپ"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"اسٹوریج"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"اشارات"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"فوری ایپس"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> چل رہی ہے"</string> <string name="instant_apps_message" msgid="6112428971833011754">"انسٹال کیے بغیر کھلنے والی ایپ۔"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ایکسیسبیلٹی خصوصیات کھولنے کے لیے تھپتھپائیں۔ ترتیبات میں اس بٹن کو حسب ضرورت بنائیں یا تبدیل کریں۔\n\n"<annotation id="link">"ترتیبات ملاحظہ کریں"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"عارضی طور پر بٹن کو چھپانے کے لئے اسے کنارے پر لے جائیں"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"کالعدم کریں"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> شارٹ کٹ ہٹا دیا گیا"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# شارٹ کٹ ہٹا دیا گیا}other{# شارٹ کٹس ہٹا دیے گئے}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"اوپر بائیں جانب لے جائیں"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"صارف کی موجودگی کا پتہ چلا ہے"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string> <string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"جاری رکھنے کے لیے سوائپ کریں"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"آپ کے اندرونی ڈسپلے کو دو طرفہ مطابقت پذیر بنایا جائے گا۔ آپ کا فرنٹ ڈسپلے آف ہو جائے گا۔"</string> <string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو مرر کریں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index b9a9832ea249..67d3db87b4f1 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Yuz bilan ochish sozlanmadimi. Sozlamalarni ochib, qaytadan urining."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Barmoq izi skaneriga tegining"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Davom etish uchun qulfni ochish belgisini bosing"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Bu yuz notanish. Barmoq izi orqali urining."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Yuz aniqlanmadi"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Barmoq izi orqali urining"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Yuz bilan ochilmaydi."</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ulandi."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Quvvat olmoqda • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g> qoldi"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Qoʻllanma bilan tanishish uchun chapga suring"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vidjet muharririni ochish"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tayyor"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Sozlash"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Xotira"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Maslahatlar"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Darhol ochiladigan ilovalar"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> ishlayapti"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Ilova o‘rnatilmasdan ochildi."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Maxsus imkoniyatlarni ochish uchun bosing Sozlamalardan moslay yoki almashtira olasiz.\n\n"<annotation id="link">"Sozlamalar"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Vaqtinchalik berkitish uchun tugmani qirra tomon suring"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Bekor qilish"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"<xliff:g id="FEATURE_NAME">%s</xliff:g> ta yorliq olindi"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# ta yorliq olindi}other{# ta yorliq olindi}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuqori chapga surish"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Foydalanuvchi aniqlandi"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string> <string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Davom etish uchun suring"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ichki ekran uchun aks ettirish yoqiladi. Old ekran oʻchiriladi."</string> <string name="mirror_display" msgid="2515262008898122928">"Displeyni aks ettirish"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index b1ff9a86ee6e..e4ae7be3b544 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Không thiết lập được tính năng Mở khoá bằng khuôn mặt. Hãy chuyển đến phần Cài đặt để thử lại."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Chạm vào cảm biến vân tay"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Nhấn vào biểu tượng mở khoá để tiếp tục"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Không thể nhận dạng khuôn mặt. Hãy dùng vân tay."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Không nhận ra khuôn mặt"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Hãy dùng vân tay"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Không dùng được tính năng Mở khoá bằng khuôn mặt"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Đã kết nối bluetooth."</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Đang sạc • Sẽ đầy sau <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Vuốt sang trái để bắt đầu xem hướng dẫn chung"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Mở trình chỉnh sửa tiện ích"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Xong"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Thiết lập"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Bộ nhớ"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Gợi ý"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Ứng dụng tức thì"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> đang chạy"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Ứng dụng được mở mà không cần cài đặt."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Nhấn để mở bộ tính năng hỗ trợ tiếp cận. Tuỳ chỉnh/thay thế nút này trong phần Cài đặt.\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Di chuyển nút sang cạnh để ẩn nút tạm thời"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Huỷ"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Đã xoá phím tắt dành cho <xliff:g id="FEATURE_NAME">%s</xliff:g>"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Đã xoá # lối tắt}other{Đã xoá # lối tắt}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Phát hiện thấy người dùng đang hiện diện"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string> <string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Vuốt để tiếp tục"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Phản chiếu sang màn hình ngoài?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Màn hình trong của bạn sẽ được phản chiếu. Màn hình ngoài của bạn sẽ tắt."</string> <string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 237fd572530f..7fd84d918038 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"无法设置“人脸解锁”功能。请前往“设置”重试。"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"请触摸指纹传感器"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"按下解锁图标即可继续"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"无法识别人脸。请改用指纹。"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"人脸识别失败"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"改用指纹"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"无法使用人脸解锁功能"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"蓝牙已连接。"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 正在充电 • 将于 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>后充满"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑动即可启动公共教程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"打开微件编辑器"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"设置"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"存储空间"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"免安装应用"</string> <string name="instant_apps_title" msgid="8942706782103036910">"正在运行<xliff:g id="APP">%1$s</xliff:g>"</string> <string name="instant_apps_message" msgid="6112428971833011754">"已打开免安装应用。"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"点按即可打开无障碍功能。您可在“设置”中自定义或更换此按钮。\n\n"<annotation id="link">"查看设置"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"将按钮移到边缘,即可暂时将其隐藏"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"撤消"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"已移除“<xliff:g id="FEATURE_NAME">%s</xliff:g>”快捷方式"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{已移除 # 个快捷方式}other{已移除 # 个快捷方式}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移至左上角"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"检测到用户存在"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string> <string name="install_app" msgid="5066668100199613936">"安装应用"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑动可继续操作"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"系统将镜像您的内屏,而关闭外屏。"</string> <string name="mirror_display" msgid="2515262008898122928">"镜像到显示屏"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 313af30bf5a6..568f8232f45a 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"無法設定「面孔解鎖」功能,請前往「設定」再試一次。"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"按解鎖圖示即可繼續"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識面孔,請改用指紋完成驗證。"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識面孔"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"無法使用面孔解鎖"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充滿電"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑動即可開始共用教學課程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"開啟小工具編輯器"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"設定"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> 運作中"</string> <string name="instant_apps_message" msgid="6112428971833011754">"已開啟免安裝應用程式。"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"㩒一下就可以開無障礙功能。喺「設定」度自訂或者取代呢個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣即可暫時隱藏"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"復原"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"已移除「<xliff:g id="FEATURE_NAME">%s</xliff:g>」捷徑"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{已移除 # 個捷徑}other{已移除 # 個捷徑}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移去左上方"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者動態"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"輕掃即可繼續瀏覽"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內部螢幕,前方螢幕則會關閉。"</string> <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 6a13d3dc22a5..86e653547d6f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"無法設定人臉解鎖功能,請前往「設定」再試一次。"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"請輕觸指紋感應器"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"按下「解鎖」圖示即可繼續操作"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"無法辨識臉孔,請改用指紋完成驗證。"</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"無法辨識臉孔"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"請改用指紋"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"無法使用人臉解鎖功能"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"藍牙連線已建立。"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • 充電中 • 將於 <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>後充飽"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"向左滑動即可啟動通用教學課程"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"開啟小工具編輯器"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"設定"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"儲存空間"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"提示"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"免安裝應用程式"</string> <string name="instant_apps_title" msgid="8942706782103036910">"正在執行「<xliff:g id="APP">%1$s</xliff:g>」"</string> <string name="instant_apps_message" msgid="6112428971833011754">"已開啟免安裝應用程式。"</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"輕觸即可開啟無障礙功能。你可以前往「設定」自訂或更換這個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣處即可暫時隱藏"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"復原"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"已移除「<xliff:g id="FEATURE_NAME">%s</xliff:g>」捷徑"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{已移除 # 個捷徑}other{已移除 # 個捷徑}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移到左上方"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string> <string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑動畫面繼續瀏覽"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內螢幕,封面螢幕則會關閉。"</string> <string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 23862a78b9d9..564ba337b1d3 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -188,10 +188,12 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"Ayikwazanga ukusetha ukuvula ngobuso. Iya Kumasethingi ukuze uzame futhi."</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Thinta inzwa yesigxivizo zeminwe"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"Cindezela isithonjana sokuvula ukuze uqhubeke"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Ayibazi ubuso. Sebenzisa izigxivizo zeminwe kunalokho."</string> + <!-- no translation found for fingerprint_dialog_use_fingerprint_instead (5542430577183894219) --> + <skip /> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="9044619102286917151">"Ayikwazi ukubona ubuso"</string> + <!-- no translation found for keyguard_face_failed (2346762871330729634) --> + <skip /> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"Kunalokho sebenzisa isigxivizo somunwe"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"Ukuvula ngobuso akutholakali"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth ixhunyiwe"</string> @@ -413,6 +415,16 @@ <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Iyashaja • Izogcwala ngo-<xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string> <string name="communal_tutorial_indicator_text" msgid="4503010353591430123">"Swayiphela kwesokunxele ukuze uqale okokufundisa komphakathi"</string> <string name="button_to_open_widget_editor" msgid="5599945944349057600">"Vula isihleli sewijethi"</string> + <!-- no translation found for cta_tile_button_to_open_widget_editor (3871562362382963878) --> + <skip /> + <!-- no translation found for cta_tile_button_to_dismiss (3377597875997861754) --> + <skip /> + <!-- no translation found for cta_label_to_edit_widget (6496885074209203756) --> + <skip /> + <!-- no translation found for cta_label_to_open_widget_picker (3874946756976360699) --> + <skip /> + <!-- no translation found for popup_on_dismiss_cta_tile_text (8292501780996070019) --> + <skip /> <string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string> <string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kwenziwe"</string> @@ -834,6 +846,8 @@ <string name="notification_channel_setup" msgid="7660580986090760350">"Ukusetha"</string> <string name="notification_channel_storage" msgid="2720725707628094977">"Isitoreji"</string> <string name="notification_channel_hints" msgid="7703783206000346876">"Ukubonisa"</string> + <!-- no translation found for notification_channel_accessibility (8956203986976245820) --> + <skip /> <string name="instant_apps" msgid="8337185853050247304">"Izinhlelo zokusebenza ezisheshayo"</string> <string name="instant_apps_title" msgid="8942706782103036910">"<xliff:g id="APP">%1$s</xliff:g> esebenzayo"</string> <string name="instant_apps_message" msgid="6112428971833011754">"Uhlelo lokusebenza luvulwe ngaphndle kokufakwa."</string> @@ -929,6 +943,10 @@ <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Thepha ukuze uvule izakhi zokufinyelela. Enza ngendlela oyifisayo noma shintsha le nkinobho Kumasethingi.\n\n"<annotation id="link">"Buka amasethingi"</annotation></string> <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Hambisa inkinobho onqenqemeni ukuze uyifihle okwesikhashana"</string> <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Hlehlisa"</string> + <!-- no translation found for accessibility_floating_button_hidden_notification_title (4115036997406994799) --> + <skip /> + <!-- no translation found for accessibility_floating_button_hidden_notification_text (1457021647040915658) --> + <skip /> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Isinqamuleli se-<xliff:g id="FEATURE_NAME">%s</xliff:g> sisusiwe"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{Isinqamuleli esingu-# sisusiwe}one{Izinqamuleli ezingu-# zisusiwe}other{Izinqamuleli ezingu-# zisusiwe}}"</string> <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Hamba phezulu kwesokunxele"</string> @@ -1207,6 +1225,7 @@ <string name="assistant_attention_content_description" msgid="4166330881435263596">"Ubukhona bomsebenzisi butholakele"</string> <string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string> <string name="install_app" msgid="5066668100199613936">"Faka i-app"</string> + <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swayipha ukuze uqhubeke"</string> <string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string> <string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Isibonisi sakho sangaphakathi sizoboniswa. Isibonisi sakho sangaphambili sizovalwa."</string> <string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 5f6a39a91b8b..8be1cc7282e3 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -135,6 +135,9 @@ <color name="biometric_dialog_gray">#ff757575</color> <color name="biometric_dialog_accent">@color/material_dynamic_primary40</color> <color name="biometric_dialog_error">#ffd93025</color> <!-- red 600 --> + <!-- Color for biometric prompt content view --> + <color name="biometric_prompt_content_background_color">#8AB4F8</color> + <color name="biometric_prompt_content_list_item_bullet_color">#1d873b</color> <!-- SFPS colors --> <color name="sfps_chevron_fill">@color/material_dynamic_primary90</color> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 90d8cdb724e4..798fc06b44f7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1092,6 +1092,16 @@ <dimen name="biometric_dialog_width">240dp</dimen> <dimen name="biometric_dialog_height">240dp</dimen> + <!-- Dimensions for biometric prompt content view. --> + <dimen name="biometric_prompt_space_above_content">48dp</dimen> + <dimen name="biometric_prompt_content_container_padding_horizontal">24dp</dimen> + <dimen name="biometric_prompt_content_padding_horizontal">10dp</dimen> + <dimen name="biometric_prompt_content_list_row_height">24dp</dimen> + <dimen name="biometric_prompt_content_list_item_padding_horizontal">10dp</dimen> + <dimen name="biometric_prompt_content_list_item_text_size">14sp</dimen> + <dimen name="biometric_prompt_content_list_item_bullet_gap_width">10dp</dimen> + <dimen name="biometric_prompt_content_list_item_bullet_radius">5dp</dimen> + <!-- Biometric Auth Credential values --> <dimen name="biometric_auth_icon_size">48dp</dimen> diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml index c925b26c27ff..fad4d4ff8abe 100644 --- a/packages/SystemUI/res/values/integers.xml +++ b/packages/SystemUI/res/values/integers.xml @@ -16,6 +16,7 @@ --> <resources> <integer name="biometric_dialog_text_gravity">8388611</integer> <!-- gravity start --> + <integer name="biometric_prompt_content_list_item_max_lines_if_two_column">3</integer> <integer name="qs_security_footer_maxLines">2</integer> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 3f11faebffb1..19895897ef31 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -449,11 +449,11 @@ <!-- Content description after successful auth when confirmation required --> <string name="fingerprint_dialog_authenticated_confirmation">Press the unlock icon to continue</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> - <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string> + <string name="fingerprint_dialog_use_fingerprint_instead">Face not recognized. Use fingerprint instead.</string> <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] --> <string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string> <!-- Message shown to inform the user a face cannot be recognized. [CHAR LIMIT=25] --> - <string name="keyguard_face_failed">Can\u2019t recognize face</string> + <string name="keyguard_face_failed">Face not recognized</string> <!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] --> <string name="keyguard_suggest_fingerprint">Use fingerprint instead</string> <!-- Message shown to inform the user that face unlock is not available. [CHAR LIMIT=59] --> @@ -1087,6 +1087,8 @@ <string name="cta_label_to_edit_widget">Add, remove, and reorder your widgets in this space</string> <!-- Label for CTA tile that opens widget picker on click in edit mode [CHAR LIMIT=50] --> <string name="cta_label_to_open_widget_picker">Add more widgets</string> + <!-- Text for the popup to be displayed after dismissing the CTA tile. [CHAR LIMIT=50] --> + <string name="popup_on_dismiss_cta_tile_text">Long press to customize widgets</string> <!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] --> <string name="button_to_remove_widget">Remove</string> <!-- Text for the button that launches the hub mode widget picker. [CHAR LIMIT=50] --> @@ -1610,37 +1612,9 @@ <!-- Bluetooth enablement ok text [CHAR LIMIT=40] --> <string name="enable_bluetooth_confirmation_ok">Turn on</string> - <!-- [CHAR LIMIT=NONE] Importance Tuner setting title --> - <string name="tuner_full_importance_settings">Power notification controls</string> - <!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description --> <string name="rotation_lock_camera_rotation_on">On - Face-based</string> - <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications. - \n\n<b>Level 5</b> - \n- Show at the top of the notification list - \n- Allow full screen interruption - \n- Always peek - \n\n<b>Level 4</b> - \n- Prevent full screen interruption - \n- Always peek - \n\n<b>Level 3</b> - \n- Prevent full screen interruption - \n- Never peek - \n\n<b>Level 2</b> - \n- Prevent full screen interruption - \n- Never peek - \n- Never make sound and vibration - \n\n<b>Level 1</b> - \n- Prevent full screen interruption - \n- Never peek - \n- Never make sound or vibrate - \n- Hide from lock screen and status bar - \n- Show at the bottom of the notification list - \n\n<b>Level 0</b> - \n- Block all notifications from the app - </string> - <!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] --> <string name="inline_done_button">Done</string> @@ -2282,6 +2256,8 @@ <string name="notification_channel_storage">Storage</string> <!-- Title for the notification channel for hints and suggestions. [CHAR LIMIT=NONE] --> <string name="notification_channel_hints">Hints</string> + <!-- Title for the notification channel for accessibility related (i.e. accessibility floating menu). [CHAR LIMIT=NONE] --> + <string name="notification_channel_accessibility">Accessibility</string> <!-- App label of the instant apps notification [CHAR LIMIT=60] --> <string name="instant_apps">Instant Apps</string> @@ -2552,6 +2528,11 @@ <string name="accessibility_floating_button_docking_tooltip">Move button to the edge to hide it temporarily</string> <!-- Text for the undo action button of the message view of the accessibility floating menu to perform undo operation. [CHAR LIMIT=30]--> <string name="accessibility_floating_button_undo">Undo</string> + <!-- Notification title shown when accessibility floating button is in hidden state. [CHAR LIMIT=NONE] --> + <string name="accessibility_floating_button_hidden_notification_title">Accessibility button hidden</string> + <!-- Notification content text to explain user can tap notification to bring back accessibility floating button. [CHAR LIMIT=NONE] --> + <string name="accessibility_floating_button_hidden_notification_text">Tap to show accessibility button</string> + <!-- Text for the message view with undo action of the accessibility floating menu to show which feature shortcut was removed. [CHAR LIMIT=30]--> <string name="accessibility_floating_button_undo_message_label_text"><xliff:g id="feature name" example="Magnification">%s</xliff:g> shortcut removed</string> <!-- Text for the message view with undo action of the accessibility floating menu to show how many features shortcuts were removed. [CHAR LIMIT=30]--> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 7d7c050a666c..ab3cacb27191 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -195,6 +195,24 @@ <item name="android:textSize">14sp</item> </style> + <style name="TextAppearance.AuthCredential.ContentViewTitle"> + <item name="android:fontFamily">google-sans</item> + <item name="android:paddingTop">8dp</item> + <item name="android:paddingHorizontal">24dp</item> + <item name="android:textSize">14sp</item> + <item name="android:gravity">start</item> + </style> + + <style name="TextAppearance.AuthCredential.ContentViewListItem"> + <item name="android:fontFamily">google-sans</item> + <item name="android:paddingTop">8dp</item> + <item name="android:paddingHorizontal"> + @dimen/biometric_prompt_content_list_item_padding_horizontal + </item> + <item name="android:textSize">@dimen/biometric_prompt_content_list_item_text_size</item> + <item name="android:gravity">start</item> + </style> + <style name="TextAppearance.AuthCredential.Error"> <item name="android:paddingTop">6dp</item> <item name="android:paddingHorizontal">24dp</item> @@ -294,6 +312,11 @@ <item name="android:textSize">16sp</item> </style> + <style name="AuthCredentialContentLayoutStyle"> + <item name="android:background">@color/biometric_prompt_content_background_color</item> + <item name="android:paddingHorizontal">@dimen/biometric_prompt_content_padding_horizontal</item> + </style> + <style name="DeviceManagementDialogTitle"> <item name="android:gravity">center</item> <item name="android:textAppearance">@style/TextAppearance.Dialog.Title</item> diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml deleted file mode 100644 index 7719d5e03df0..000000000000 --- a/packages/SystemUI/res/xml/other_settings.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2016 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:sysui="http://schemas.android.com/apk/res-auto" - android:title="@string/other"> - - <!-- importance --> - <Preference - android:key="power_notification_controls" - android:title="@string/tuner_full_importance_settings" - android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/> - -</PreferenceScreen> diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 05106c904d3d..326c7ef52fce 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -34,9 +34,6 @@ java_library { srcs: [ ":statslog-SystemUI-java-gen", ], - lint: { - baseline_filename: "lint-baseline.xml", - }, } android_library { @@ -74,9 +71,6 @@ android_library { min_sdk_version: "current", plugins: ["dagger2-compiler"], kotlincflags: ["-Xjvm-default=all"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } java_library { @@ -88,9 +82,6 @@ java_library { static_kotlin_stdlib: false, java_version: "1.8", min_sdk_version: "current", - lint: { - baseline_filename: "lint-baseline.xml", - }, } java_library { @@ -110,7 +101,4 @@ java_library { }, java_version: "1.8", min_sdk_version: "current", - lint: { - baseline_filename: "lint-baseline.xml", - }, } diff --git a/packages/SystemUI/shared/lint-baseline.xml b/packages/SystemUI/shared/lint-baseline.xml deleted file mode 100644 index 4bd6729227e8..000000000000 --- a/packages/SystemUI/shared/lint-baseline.xml +++ /dev/null @@ -1,708 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev"> - - <issue - id="NewApi" - message="Call requires API level R (current min is 26): `android.os.RemoteException#rethrowFromSystemServer`" - errorLine1=" throw e.rethrowFromSystemServer();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java" - line="90" - column="21"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `android.graphics.Bitmap#getHardwareBuffer`" - errorLine1=" mBuffer != null ? mBuffer.getHardwareBuffer() : null, mRect);" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java" - line="39" - column="43"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `new android.graphics.ParcelableColorSpace`" - errorLine1=" ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="57" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `new android.graphics.ParcelableColorSpace`" - errorLine1=" : new ParcelableColorSpace(bitmap.getColorSpace());" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="58" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `android.graphics.Bitmap#getHardwareBuffer`" - errorLine1=" bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="61" - column="49"/> - </issue> - - <issue - id="NewApi" - message="Cast from `ParcelableColorSpace` to `Parcelable` requires API level 31 (current min is 26)" - errorLine1=" bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);" - errorLine2=" ~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="62" - column="47"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.graphics.Bitmap#wrapHardwareBuffer`" - errorLine1=" return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer)," - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="84" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `android.graphics.ParcelableColorSpace#getColorSpace`" - errorLine1=" colorSpace.getColorSpace());" - errorLine2=" ~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java" - line="85" - column="28"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`" - errorLine1=" final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java" - line="122" - column="47"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.util.ArraySet`" - errorLine1=" mPluginActions = new ArraySet<>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null));" - errorLine2=" ~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java" - line="41" - column="26"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.util.ArraySet`" - errorLine1=" return new ArraySet<>(mPluginActions);" - errorLine2=" ~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java" - line="45" - column="16"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 28 (current min is 26): `android.graphics.Bitmap#createBitmap`" - errorLine1=" return Bitmap.createBitmap(picture);" - errorLine2=" ~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java" - line="113" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Builder`" - errorLine1=" mSurface = new SurfaceControl.Builder()" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="116" - column="24"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#setName`" - errorLine1=" .setName("Transition Unrotate")" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="117" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#setParent`" - errorLine1=" .setParent(parent)" - errorLine2=" ~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="119" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#build`" - errorLine1=" .build();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="120" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#reparent`" - errorLine1=" t.reparent(child, mSurface);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="137" - column="15"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`" - errorLine1=" SurfaceControl.Transaction t = new SurfaceControl.Transaction();" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="143" - column="44"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#reparent`" - errorLine1=" t.reparent(mRotateChildren.get(i), rootLeash);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="145" - column="19"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" t.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="148" - column="15"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(counterLauncher.mSurface, launcherLayer);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="200" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="206" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(leash, info.getChanges().size() * 3 - i);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="216" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`" - errorLine1=" t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="223" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(counterWallpaper.mSurface, -1);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="233" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" t.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java" - line="238" - column="19"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#taskId`" - errorLine1=" taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="101" - column="49"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`" - errorLine1=" taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="192" - column="49"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#isRunning`" - errorLine1=" isNotInRecents = !change.getTaskInfo().isRunning;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="116" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#isRunning`" - errorLine1=" isNotInRecents = !change.getTaskInfo().isRunning;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="210" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#release`" - errorLine1=" leash.mSurfaceControl.release();" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="159" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#release`" - errorLine1=" mStartLeash.release();" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java" - line="161" - column="25"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(change.getLeash(), info.getChanges().size() * 3 - i);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java" - line="97" - column="27"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`" - errorLine1=" t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java" - line="105" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" t.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java" - line="107" - column="19"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#isValid`" - errorLine1=" return mSurfaceControl != null && mSurfaceControl.isValid();" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java" - line="41" - column="59"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#release`" - errorLine1=" mSurfaceControlViewHost.release();" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java" - line="61" - column="37"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level R (current min is 26): `android.view.SurfaceView#getHostToken`" - errorLine1=" bundle.putBinder(KEY_HOST_TOKEN, surfaceView.getHostToken());" - errorLine2=" ~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java" - line="34" - column="54"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceView#getSurfaceControl`" - errorLine1=" bundle.putParcelable(KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl());" - errorLine2=" ~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java" - line="35" - column="63"/> - </issue> - - <issue - id="NewApi" - message="Cast from `SurfaceControl` to `Parcelable` requires API level 29 (current min is 26)" - errorLine1=" bundle.putParcelable(KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl());" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java" - line="35" - column="51"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#isValid`" - errorLine1=" if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {" - errorLine2=" ~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java" - line="107" - column="79"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`" - errorLine1=" Transaction t = new Transaction();" - errorLine2=" ~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java" - line="113" - column="33"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" t.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java" - line="122" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`" - errorLine1=" t.setAlpha(surface, alpha);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java" - line="361" - column="19"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" t.setLayer(surface, layer);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java" - line="364" - column="19"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#origActivity`" - errorLine1=" ComponentName sourceComponent = t.origActivity != null" - errorLine2=" ~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="73" - column="45"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#origActivity`" - errorLine1=" ? t.origActivity" - errorLine2=" ~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="75" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`" - errorLine1=" this.id = t.taskId;" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="78" - column="23"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#baseIntent`" - errorLine1=" this.baseIntent = t.baseIntent;" - errorLine2=" ~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="80" - column="31"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskDescription`" - errorLine1=" ActivityManager.TaskDescription td = taskInfo.taskDescription;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="242" - column="46"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#topActivity`" - errorLine1=" taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java" - line="246" - column="72"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#topActivity`" - errorLine1=" return info.topActivity;" - errorLine2=" ~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java" - line="49" - column="16"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskDescription`" - errorLine1=" return info.taskDescription;" - errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java" - line="53" - column="16"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#taskId`" - errorLine1=" onTaskMovedToFront(taskInfo.taskId);" - errorLine2=" ~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java" - line="70" - column="28"/> - </issue> - - <issue - id="NewApi" - message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`" - errorLine1=" onTaskMovedToFront(taskInfo.taskId);" - errorLine2=" ~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java" - line="70" - column="28"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.graphics.Bitmap#wrapHardwareBuffer`" - errorLine1=" thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());" - errorLine2=" ~~~~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java" - line="69" - column="36"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 31 (current min is 26): `android.app.WallpaperColors#getColorHints`" - errorLine1=" (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;" - errorLine2=" ~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TonalCompat.java" - line="42" - column="29"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`" - errorLine1=" mTransaction = new Transaction();" - errorLine2=" ~~~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java" - line="31" - column="24"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" mTransaction.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java" - line="35" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setBufferSize`" - errorLine1=" mTransaction.setBufferSize(surfaceControl.mSurfaceControl, w, h);" - errorLine2=" ~~~~~~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java" - line="54" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`" - errorLine1=" mTransaction.setLayer(surfaceControl.mSurfaceControl, z);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java" - line="59" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`" - errorLine1=" mTransaction.setAlpha(surfaceControl.mSurfaceControl, alpha);" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java" - line="64" - column="22"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`" - errorLine1=" t.apply();" - errorLine2=" ~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java" - line="64" - column="15"/> - </issue> - - <issue - id="NewApi" - message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`" - errorLine1=" .getFloat(Resources.getSystem().getIdentifier(" - errorLine2=" ~~~~~~~~"> - <location - file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java" - line="46" - column="18"/> - </issue> - -</issues> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java index 387f2e1aa430..87cc86f18fdc 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java @@ -38,6 +38,7 @@ import dalvik.system.PathClassLoader; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -57,7 +58,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager private final PluginFactory<T> mPluginFactory; private final String mTag; - private boolean mIsDebug = false; + private BiConsumer<String, String> mLogConsumer = null; private Context mPluginContext; private T mPlugin; @@ -86,17 +87,13 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager return mTag; } - public boolean getIsDebug() { - return mIsDebug; + public void setLogFunc(BiConsumer logConsumer) { + mLogConsumer = logConsumer; } - public void setIsDebug(boolean debug) { - mIsDebug = debug; - } - - private void logDebug(String message) { - if (mIsDebug) { - Log.i(mTag, message); + private void log(String message) { + if (mLogConsumer != null) { + mLogConsumer.accept(mTag, message); } } @@ -105,19 +102,19 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager boolean loadPlugin = mListener.onPluginAttached(this); if (!loadPlugin) { if (mPlugin != null) { - logDebug("onCreate: auto-unload"); + log("onCreate: auto-unload"); unloadPlugin(); } return; } if (mPlugin == null) { - logDebug("onCreate auto-load"); + log("onCreate auto-load"); loadPlugin(); return; } - logDebug("onCreate: load callbacks"); + log("onCreate: load callbacks"); mPluginFactory.checkVersion(mPlugin); if (!(mPlugin instanceof PluginFragment)) { // Only call onCreate for plugins that aren't fragments, as fragments @@ -129,7 +126,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager /** Alerts listener and plugin that the plugin is being shutdown. */ public synchronized void onDestroy() { - logDebug("onDestroy"); + log("onDestroy"); unloadPlugin(); mListener.onPluginDetached(this); } @@ -145,7 +142,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager */ public synchronized void loadPlugin() { if (mPlugin != null) { - logDebug("Load request when already loaded"); + log("Load request when already loaded"); return; } @@ -157,7 +154,7 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager return; } - logDebug("Loaded plugin; running callbacks"); + log("Loaded plugin; running callbacks"); mPluginFactory.checkVersion(mPlugin); if (!(mPlugin instanceof PluginFragment)) { // Only call onCreate for plugins that aren't fragments, as fragments @@ -174,11 +171,11 @@ public class PluginInstance<T extends Plugin> implements PluginLifecycleManager */ public synchronized void unloadPlugin() { if (mPlugin == null) { - logDebug("Unload request when already unloaded"); + log("Unload request when already unloaded"); return; } - logDebug("Unloading plugin, running callbacks"); + log("Unloading plugin, running callbacks"); mListener.onPluginUnloaded(mPlugin, this); if (!(mPlugin instanceof PluginFragment)) { // Only call onDestroy for plugins that aren't fragments, as fragments diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index 823bd2d147d3..7088829bd2a3 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -88,18 +88,23 @@ oneway interface IOverviewProxy { */ void onNavButtonsDarkIntensityChanged(float darkIntensity) = 22; - /** - * Sent when split keyboard shortcut is triggered to enter stage split. - */ - void enterStageSplitFromRunningApp(boolean leftOrTop) = 25; - - /** - * Sent when the surface for navigation bar is created or changed - */ - void onNavigationBarSurface(in SurfaceControl surface) = 26; - - /** - * Sent when the task bar stash state is toggled. - */ - void onTaskbarToggled() = 27; + /** + * Sent when when navigation bar luma sampling is enabled or disabled. + */ + void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) = 23; + + /** + * Sent when split keyboard shortcut is triggered to enter stage split. + */ + void enterStageSplitFromRunningApp(boolean leftOrTop) = 25; + + /** + * Sent when the surface for navigation bar is created or changed + */ + void onNavigationBarSurface(in SurfaceControl surface) = 26; + + /** + * Sent when the task bar stash state is toggled. + */ + void onTaskbarToggled() = 27; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index 74b975cb7232..de7c12db6b11 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -22,6 +22,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static com.android.keyguard.KeyguardClockSwitch.LARGE; import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.Flags.migrateClocksToBlueprint; +import static com.android.systemui.Flags.smartspaceRelocateToBottom; import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; @@ -421,6 +422,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS return; } + if (smartspaceRelocateToBottom()) { + return; + } + mSmartspaceView = mSmartspaceController.buildAndConnectView(mView); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( MATCH_PARENT, WRAP_CONTENT); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index e457ca18d071..8e5d0dac7bef 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -1111,7 +1111,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } private boolean canDisplayUserSwitcher() { - return mFeatureFlags.isEnabled(Flags.BOUNCER_USER_SWITCHER); + return getContext().getResources().getBoolean(R.bool.config_enableBouncerUserSwitcher); } private void configureMode() { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java index c5e70703cd2b..5729119a582a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java @@ -105,6 +105,13 @@ public class KeyguardSimPinViewController @Override protected void onViewAttached() { super.onViewAttached(); + mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); + } + + @Override + protected void onViewDetached() { + super.onViewDetached(); + mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); } @Override @@ -128,14 +135,12 @@ public class KeyguardSimPinViewController @Override public void onResume(int reason) { super.onResume(reason); - mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mView.resetState(); } @Override public void onPause() { super.onPause(); - mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback); // dismiss the dialog. if (mSimUnlockProgressDialog != null) { diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java index 2a54a4eee657..d372f5a616b1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java @@ -20,6 +20,7 @@ import static androidx.constraintlayout.widget.ConstraintSet.END; import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID; import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_CLOCK_MOVE_ANIMATION; +import static com.android.systemui.Flags.migrateClocksToBlueprint; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; import android.animation.Animator; @@ -492,7 +493,12 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV boolean splitShadeEnabled, boolean shouldBeCentered, boolean animate) { - mKeyguardClockSwitchController.setSplitShadeCentered(splitShadeEnabled && shouldBeCentered); + if (migrateClocksToBlueprint()) { + mKeyguardInteractor.setClockShouldBeCentered(mSplitShadeEnabled && shouldBeCentered); + } else { + mKeyguardClockSwitchController.setSplitShadeCentered( + splitShadeEnabled && shouldBeCentered); + } if (mStatusViewCentered == shouldBeCentered) { return; } @@ -548,8 +554,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV ClockController clock = mKeyguardClockSwitchController.getClock(); boolean customClockAnimation = clock != null && clock.getLargeClock().getConfig().getHasCustomPositionUpdatedAnimation(); - - if (customClockAnimation) { + // When migrateClocksToBlueprint is on, customized clock animation is conducted in + // KeyguardClockViewBinder + if (customClockAnimation && !migrateClocksToBlueprint()) { // Find the clock, so we can exclude it from this transition. FrameLayout clockContainerView = mView.findViewById(R.id.lockscreen_clock_view_large); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java index 49e0df6f6afc..568b24dbd4f3 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java @@ -24,6 +24,7 @@ import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.dynamicanimation.animation.DynamicAnimation; +import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.common.bubbles.DismissView; import com.android.wm.shell.common.magnetictarget.MagnetizedObject; @@ -116,6 +117,11 @@ class DragToInteractAnimationController { mMagnetizedObject.setMagnetListener(magnetListener); } + @VisibleForTesting + MagnetizedObject.MagnetListener getMagnetListener() { + return mMagnetizedObject.getMagnetListener(); + } + void maybeConsumeDownMotionEvent(MotionEvent event) { mMagnetizedObject.maybeConsumeMotionEvent(event); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java new file mode 100644 index 000000000000..b5eeaa18447e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023 The Android Open 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.accessibility.floatingmenu; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; + +import com.android.systemui.res.R; +import com.android.systemui.util.NotificationChannels; + +class MenuNotificationFactory { + public static final String ACTION_UNDO = + "com.android.systemui.accessibility.floatingmenu.action.UNDO"; + public static final String ACTION_DELETE = + "com.android.systemui.accessibility.floatingmenu.action.DELETE"; + + private final Context mContext; + + MenuNotificationFactory(Context context) { + mContext = context; + } + + public Notification createHiddenNotification() { + final CharSequence title = mContext.getText( + R.string.accessibility_floating_button_hidden_notification_title); + final CharSequence content = mContext.getText( + R.string.accessibility_floating_button_hidden_notification_text); + + return new Notification.Builder(mContext, NotificationChannels.ALERTS) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(R.drawable.ic_settings_24dp) + .setContentIntent(buildUndoIntent()) + .setDeleteIntent(buildDeleteIntent()) + .setColor(mContext.getResources().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_SYSTEM) + .build(); + } + + private PendingIntent buildUndoIntent() { + final Intent intent = new Intent(ACTION_UNDO); + + return PendingIntent.getBroadcast(mContext, /* requestCode= */ 0, intent, + PendingIntent.FLAG_IMMUTABLE); + + } + + private PendingIntent buildDeleteIntent() { + final Intent intent = new Intent(ACTION_DELETE); + + return PendingIntent.getBroadcastAsUser(mContext, /* requestCode= */ 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT); + + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java index 62d5feb7d024..6869bbaedcf3 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java @@ -26,16 +26,21 @@ import static com.android.internal.accessibility.common.ShortcutConstants.Access import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType; import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState; import static com.android.systemui.accessibility.floatingmenu.MenuMessageView.Index; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_DELETE; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_UNDO; import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.IntDef; import android.annotation.StringDef; import android.annotation.SuppressLint; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentCallbacks; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; @@ -58,6 +63,7 @@ import androidx.lifecycle.Observer; import com.android.internal.accessibility.dialog.AccessibilityTarget; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.util.Preconditions; import com.android.systemui.Flags; import com.android.systemui.res.R; @@ -91,6 +97,8 @@ class MenuViewLayer extends FrameLayout implements private final MenuViewAppearance mMenuViewAppearance; private final MenuAnimationController mMenuAnimationController; private final AccessibilityManager mAccessibilityManager; + private final NotificationManager mNotificationManager; + private final MenuNotificationFactory mNotificationFactory; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final IAccessibilityFloatingMenu mFloatingMenu; private final SecureSettings mSecureSettings; @@ -103,7 +111,9 @@ class MenuViewLayer extends FrameLayout implements private final Rect mImeInsetsRect = new Rect(); private boolean mIsMigrationTooltipShowing; private boolean mShouldShowDockTooltip; + private boolean mIsNotificationShown; private Optional<MenuEduTooltipView> mEduTooltipView = Optional.empty(); + private BroadcastReceiver mNotificationActionReceiver; @IntDef({ LayerIndex.MENU_VIEW, @@ -184,10 +194,16 @@ class MenuViewLayer extends FrameLayout implements mMenuViewAppearance = new MenuViewAppearance(context, windowManager); mMenuView = new MenuView(context, mMenuViewModel, mMenuViewAppearance); mMenuAnimationController = mMenuView.getMenuAnimationController(); - mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage); + if (Flags.floatingMenuDragToHide()) { + mMenuAnimationController.setDismissCallback(this::hideMenuAndShowNotification); + } else { + mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage); + } mMenuAnimationController.setSpringAnimationsEndAction(this::onSpringAnimationsEndAction); mDismissView = new DismissView(context); DismissViewUtils.setup(mDismissView); + mNotificationFactory = new MenuNotificationFactory(context); + mNotificationManager = context.getSystemService(NotificationManager.class); mDragToInteractAnimationController = new DragToInteractAnimationController( mDismissView, mMenuView); mDragToInteractAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() { @@ -204,7 +220,11 @@ class MenuViewLayer extends FrameLayout implements @Override public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { - hideMenuAndShowMessage(); + if (Flags.floatingMenuDragToHide()) { + hideMenuAndShowNotification(); + } else { + hideMenuAndShowMessage(); + } mDismissView.hide(); mDragToInteractAnimationController.animateDismissMenu(/* scaleUp= */ false); } @@ -218,18 +238,25 @@ class MenuViewLayer extends FrameLayout implements mMessageView = new MenuMessageView(context); mMenuView.setOnTargetFeaturesChangeListener(newTargetFeatures -> { - if (newTargetFeatures.size() < 1) { - return; - } - - // During the undo action period, the pending action will be canceled and undo back - // to the previous state if users did any action related to the accessibility features. - if (mMessageView.getVisibility() == VISIBLE) { + if (Flags.floatingMenuDragToHide()) { + dismissNotification(); undo(); - } + } else { + if (newTargetFeatures.size() < 1) { + return; + } + + // During the undo action period, the pending action will be canceled and undo back + // to the previous state if users did any action related to the accessibility + // features. + if (mMessageView.getVisibility() == VISIBLE) { + undo(); + } - final TextView messageText = (TextView) mMessageView.getChildAt(Index.TEXT_VIEW); - messageText.setText(getMessageText(newTargetFeatures)); + + final TextView messageText = (TextView) mMessageView.getChildAt(Index.TEXT_VIEW); + messageText.setText(getMessageText(newTargetFeatures)); + } }); addView(mMenuView, LayerIndex.MENU_VIEW); @@ -456,6 +483,50 @@ class MenuViewLayer extends FrameLayout implements mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE)); } + private void hideMenuAndShowNotification() { + mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE)); + showNotification(); + } + + private void showNotification() { + registerReceiverIfNeeded(); + if (!mIsNotificationShown) { + mNotificationManager.notify( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN, + mNotificationFactory.createHiddenNotification()); + mIsNotificationShown = true; + } + } + + private void dismissNotification() { + unregisterReceiverIfNeeded(); + if (mIsNotificationShown) { + mNotificationManager.cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + mIsNotificationShown = false; + } + } + + private void registerReceiverIfNeeded() { + if (mNotificationActionReceiver != null) { + return; + } + mNotificationActionReceiver = new MenuNotificationActionReceiver(); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_UNDO); + intentFilter.addAction(ACTION_DELETE); + getContext().registerReceiver(mNotificationActionReceiver, intentFilter, + Context.RECEIVER_EXPORTED); + } + + private void unregisterReceiverIfNeeded() { + if (mNotificationActionReceiver == null) { + return; + } + getContext().unregisterReceiver(mNotificationActionReceiver); + mNotificationActionReceiver = null; + } + private void undo() { mHandler.removeCallbacksAndMessages(/* token= */ null); mMessageView.setVisibility(GONE); @@ -464,4 +535,23 @@ class MenuViewLayer extends FrameLayout implements mMenuView.setVisibility(VISIBLE); mMenuAnimationController.startGrowAnimation(); } + + @VisibleForTesting + DragToInteractAnimationController getDragToInteractAnimationController() { + return mDragToInteractAnimationController; + } + + private class MenuNotificationActionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (ACTION_UNDO.equals(action)) { + dismissNotification(); + undo(); + } else if (ACTION_DELETE.equals(action)) { + dismissNotification(); + mDismissMenuAction.run(); + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 093a1ffb4635..a40b4d733382 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -47,6 +47,7 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.FingerprintManager; +import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; @@ -1127,6 +1128,9 @@ public class AuthController implements } mCurrentDialog.dismissFromSystemServer(); + for (Callback cb : mCallbacks) { + cb.onBiometricPromptDismissed(); + } // BiometricService will have already sent the callback to the client in this case. // This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done. @@ -1156,6 +1160,15 @@ public class AuthController implements } /** + * Does the provided user have at least one optical udfps fingerprint enrolled? + */ + public boolean isOpticalUdfpsEnrolled(int userId) { + return isUdfpsEnrolled(userId) + && mUdfpsProps != null + && mUdfpsProps.get(0).sensorType == FingerprintSensorProperties.TYPE_UDFPS_OPTICAL; + } + + /** * Whether the passed userId has enrolled UDFPS. */ public boolean isUdfpsEnrolled(int userId) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index d6646378681a..81de0a283e88 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -187,7 +187,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { @Nullable private UdfpsDisplayModeProvider mUdfpsDisplayMode; // The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active. - private int mActivePointerId = -1; + private int mActivePointerId = MotionEvent.INVALID_POINTER_ID; // Whether a pointer has been pilfered for current gesture private boolean mPointerPilfered = false; // The timestamp of the most recent touch log. @@ -510,7 +510,16 @@ public class UdfpsController implements DozeReceiver, Dumpable { + mOverlay.getRequestId()); return false; } - if (!DeviceEntryUdfpsRefactor.isEnabled()) { + if (event.getAction() == MotionEvent.ACTION_DOWN + || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { + // Reset on ACTION_DOWN, start of new gesture + mPointerPilfered = false; + if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) { + Log.w(TAG, "onTouch down received without a preceding up"); + } + mActivePointerId = MotionEvent.INVALID_POINTER_ID; + mOnFingerDown = false; + } else if (!DeviceEntryUdfpsRefactor.isEnabled()) { if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f && !mAlternateBouncerInteractor.isVisibleState()) || mPrimaryBouncerInteractor.isInTransit()) { @@ -518,11 +527,6 @@ public class UdfpsController implements DozeReceiver, Dumpable { return false; } } - if (event.getAction() == MotionEvent.ACTION_DOWN - || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) { - // Reset on ACTION_DOWN, start of new gesture - mPointerPilfered = false; - } final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId, mOverlayParams); @@ -1080,7 +1084,7 @@ public class UdfpsController implements DozeReceiver, Dumpable { long gestureStart, boolean isAod) { mExecution.assertIsMainThread(); - mActivePointerId = -1; + mActivePointerId = MotionEvent.INVALID_POINTER_ID; mAcquiredReceived = false; if (mOnFingerDown) { mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java index abbfa017c13e..86802a5b58b0 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java @@ -131,23 +131,21 @@ public class UdfpsDialogMeasureAdapter { icon.measure( MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST)); - } else if (child.getId() == R.id.space_above_icon) { + } else if (child.getId() == R.id.space_above_icon + || child.getId() == R.id.space_above_content + || child.getId() == R.id.button_bar) { child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec( child.getLayoutParams().height, MeasureSpec.EXACTLY)); - } else if (child.getId() == R.id.button_bar) { - child.measure( - MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(child.getLayoutParams().height, - 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 final int clampedSpacerHeight = Math.max(mBottomSpacerHeight, 0); child.measure( MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY)); - } else if (child.getId() == R.id.description) { + } else if (child.getId() == R.id.description + || child.getId() == R.id.customized_view_container) { //skip description view and compute later continue; } else { @@ -161,27 +159,28 @@ public class UdfpsDialogMeasureAdapter { } } - //re-calculate the height of description + //re-calculate the height of body content View description = mView.findViewById(R.id.description); + View contentView = mView.findViewById(R.id.customized_view_container); if (description != null && description.getVisibility() != View.GONE) { totalHeight += measureDescription(description, displayHeight, width, totalHeight); + } else if (contentView != null && contentView.getVisibility() != View.GONE) { + totalHeight += measureDescription(contentView, displayHeight, width, totalHeight); } return new AuthDialog.LayoutParams(width, totalHeight); } - private int measureDescription(View description, int displayHeight, int currWidth, + private int measureDescription(View bodyContent, int displayHeight, int currWidth, int currHeight) { - //description view should be measured in AuthBiometricFingerprintView#onMeasureInternal - //so we could getMeasuredHeight in onMeasureInternalPortrait directly. - int newHeight = description.getMeasuredHeight() + currHeight; + int newHeight = bodyContent.getMeasuredHeight() + currHeight; int limit = (int) (displayHeight * 0.75); if (newHeight > limit) { - description.measure( + bodyContent.measure( MeasureSpec.makeMeasureSpec(currWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(limit - currHeight, MeasureSpec.EXACTLY)); } - return description.getMeasuredHeight(); + return bodyContent.getMeasuredHeight(); } @NonNull diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt new file mode 100644 index 000000000000..e6939f06b642 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractor.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2024 The Android Open 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.domain.interactor + +import android.content.Context +import android.hardware.biometrics.SensorLocationInternal +import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.shared.model.SensorLocation +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.map + +@SysUISingleton +class FingerprintPropertyInteractor +@Inject +constructor( + @Application private val context: Context, + repository: FingerprintPropertyRepository, + configurationInteractor: ConfigurationInteractor, + displayStateInteractor: DisplayStateInteractor, +) { + /** + * Devices with multiple physical displays use unique display ids to determine which sensor is + * on the active physical display. This value represents a unique physical display id. + */ + private val uniqueDisplayId: Flow<String> = + displayStateInteractor.displayChanges + .map { context.display?.uniqueId } + .filterNotNull() + .distinctUntilChanged() + + /** + * Sensor location for the: + * - current physical display + * - device's natural screen resolution + * - device's natural orientation + */ + private val unscaledSensorLocation: Flow<SensorLocationInternal> = + combine( + repository.sensorLocations, + uniqueDisplayId, + ) { locations, displayId -> + // Devices without multiple physical displays do not use the display id as the key; + // instead, the key is an empty string. + locations.getOrDefault( + displayId, + locations.getOrDefault("", SensorLocationInternal.DEFAULT) + ) + } + + /** + * Sensor location for the: + * - current physical display + * - current screen resolution + * - device's natural orientation + */ + val sensorLocation: Flow<SensorLocation> = + combine( + unscaledSensorLocation, + configurationInteractor.scaleForResolution, + ) { unscaledSensorLocation, scale -> + val sensorLocation = + SensorLocation( + unscaledSensorLocation.sensorLocationX, + unscaledSensorLocation.sensorLocationY, + unscaledSensorLocation.sensorRadius, + ) + sensorLocation.scale = scale + sensorLocation + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt index 8fbb25040f50..437793798567 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt @@ -1,5 +1,6 @@ package com.android.systemui.biometrics.domain.model +import android.hardware.biometrics.PromptContentView import android.hardware.biometrics.PromptInfo import com.android.systemui.biometrics.shared.model.BiometricModalities import com.android.systemui.biometrics.shared.model.BiometricUserInfo @@ -34,6 +35,7 @@ sealed class BiometricPromptRequest( operationInfo = operationInfo, showEmergencyCallButton = info.isShowEmergencyCallButton ) { + val contentView: PromptContentView? = info.contentView val negativeButtonText: String = info.negativeButtonText?.toString() ?: "" } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt new file mode 100644 index 000000000000..dddadbd5e036 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/shared/model/SensorLocation.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open 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.shared.model + +/** Provides current sensor location information in the current screen resolution [scale]. */ +data class SensorLocation( + private val naturalCenterX: Int, + private val naturalCenterY: Int, + private val naturalRadius: Int +) { + /** + * Scale to apply to the sensor location's natural parameters to support different screen + * resolutions. + */ + var scale: Float = 1f + + val centerX: Float + get() { + return naturalCenterX * scale + } + val centerY: Float + get() { + return naturalCenterY * scale + } + val radius: Float + get() { + return naturalRadius * scale + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricPromptLayout.java b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricPromptLayout.java index 0d72b9c07d7a..60b454e9670e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricPromptLayout.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/BiometricPromptLayout.java @@ -101,6 +101,7 @@ public class BiometricPromptLayout extends LinearLayout { final View child = getChildAt(i); if (child.getId() == R.id.space_above_icon + || child.getId() == R.id.space_above_content || child.getId() == R.id.space_below_icon || child.getId() == R.id.button_bar) { child.measure( diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt new file mode 100644 index 000000000000..22b02da5a7d5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricCustomizedViewBinder.kt @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2023 The Android Open 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.ui.binder + +import android.content.Context +import android.content.res.Resources +import android.content.res.Resources.Theme +import android.graphics.Paint +import android.hardware.biometrics.PromptContentListItem +import android.hardware.biometrics.PromptContentListItemBulletedText +import android.hardware.biometrics.PromptContentListItemPlainText +import android.hardware.biometrics.PromptContentView +import android.hardware.biometrics.PromptVerticalListContentView +import android.text.SpannableString +import android.text.Spanned +import android.text.style.BulletSpan +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import android.widget.ScrollView +import android.widget.Space +import android.widget.TextView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.biometrics.ui.BiometricPromptLayout +import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.res.R +import kotlin.math.ceil +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch + +/** Sub-binder for [BiometricPromptLayout.customized_view_container]. */ +object BiometricCustomizedViewBinder { + fun bind(customizedViewContainer: ScrollView, spaceAbove: Space, viewModel: PromptViewModel) { + customizedViewContainer.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.CREATED) { + launch { + val contentView: PromptContentView? = viewModel.contentView.first() + + if (contentView != null) { + val context = customizedViewContainer.context + customizedViewContainer.addView(contentView.toView(context)) + customizedViewContainer.visibility = View.VISIBLE + spaceAbove.visibility = View.VISIBLE + } else { + customizedViewContainer.visibility = View.GONE + spaceAbove.visibility = View.GONE + } + } + } + } + } +} + +private fun PromptContentView.toView(context: Context): View { + val resources = context.resources + val inflater = LayoutInflater.from(context) + when (this) { + is PromptVerticalListContentView -> { + val contentView = + inflater.inflate(R.layout.biometric_prompt_content_layout, null) as LinearLayout + + val descriptionView = contentView.requireViewById<TextView>(R.id.customized_view_title) + if (!description.isNullOrEmpty()) { + descriptionView.text = description + } else { + descriptionView.visibility = View.GONE + } + + // Show two column by default, once there is an item exceeding max lines, show single + // item instead. + val showTwoColumn = listItems.all { !it.doesExceedMaxLinesIfTwoColumn(resources) } + var currRowView = createNewRowLayout(inflater) + for (item in listItems) { + val itemView = item.toView(resources, inflater, context.theme) + currRowView.addView(itemView) + + if (!showTwoColumn || currRowView.childCount == 2) { + contentView.addView(currRowView) + currRowView = createNewRowLayout(inflater) + } + } + if (currRowView.childCount > 0) { + contentView.addView(currRowView) + } + + return contentView + } + else -> { + throw IllegalStateException("No such PromptContentView: $this") + } + } +} + +private fun createNewRowLayout(inflater: LayoutInflater): LinearLayout { + return inflater.inflate(R.layout.biometric_prompt_content_row_layout, null) as LinearLayout +} + +private fun PromptContentListItem.doesExceedMaxLinesIfTwoColumn( + resources: Resources, +): Boolean { + val passedInText: CharSequence = + when (this) { + is PromptContentListItemPlainText -> text + is PromptContentListItemBulletedText -> text + else -> { + throw IllegalStateException("No such ListItem: $this") + } + } + + when (this) { + is PromptContentListItemPlainText, + is PromptContentListItemBulletedText -> { + val dialogMargin = + resources.getDimensionPixelSize(R.dimen.biometric_dialog_border_padding) + val halfDialogWidth = + Resources.getSystem().displayMetrics.widthPixels / 2 - dialogMargin + val containerPadding = + resources.getDimensionPixelSize( + R.dimen.biometric_prompt_content_container_padding_horizontal + ) + val contentPadding = + resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_padding_horizontal) + val listItemPadding = getListItemPadding(resources) + val maxWidth = halfDialogWidth - containerPadding - contentPadding - listItemPadding + + val text = "$passedInText" + val textSize = + resources.getDimensionPixelSize( + R.dimen.biometric_prompt_content_list_item_text_size + ) + val paint = Paint() + paint.textSize = textSize.toFloat() + + val maxLines = + resources.getInteger( + R.integer.biometric_prompt_content_list_item_max_lines_if_two_column + ) + val numLines = ceil(paint.measureText(text).toDouble() / maxWidth).toInt() + return numLines > maxLines + } + else -> { + throw IllegalStateException("No such ListItem: $this") + } + } +} + +private fun PromptContentListItem.toView( + resources: Resources, + inflater: LayoutInflater, + theme: Theme, +): TextView { + val textView = + inflater.inflate(R.layout.biometric_prompt_content_row_item_text_view, null) as TextView + val lp = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1f) + textView.layoutParams = lp + + when (this) { + is PromptContentListItemPlainText -> { + textView.text = text + } + is PromptContentListItemBulletedText -> { + val bulletedText = SpannableString(text) + val span = + BulletSpan( + getListItemBulletGapWidth(resources), + getListItemBulletColor(resources, theme), + getListItemBulletRadius(resources) + ) + bulletedText.setSpan(span, 0 /* start */, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + textView.text = bulletedText + } + else -> { + throw IllegalStateException("No such ListItem: $this") + } + } + return textView +} + +private fun PromptContentListItem.getListItemPadding(resources: Resources): Int { + var listItemPadding = + resources.getDimensionPixelSize( + R.dimen.biometric_prompt_content_list_item_padding_horizontal + ) * 2 + when (this) { + is PromptContentListItemPlainText -> {} + is PromptContentListItemBulletedText -> { + listItemPadding += + getListItemBulletRadius(resources) * 2 + getListItemBulletGapWidth(resources) + } + else -> { + throw IllegalStateException("No such ListItem: $this") + } + } + return listItemPadding +} + +private fun getListItemBulletRadius(resources: Resources): Int = + resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_list_item_bullet_radius) + +private fun getListItemBulletGapWidth(resources: Resources): Int = + resources.getDimensionPixelSize(R.dimen.biometric_prompt_content_list_item_bullet_gap_width) + +private fun getListItemBulletColor(resources: Resources, theme: Theme): Int = + resources.getColor(R.color.biometric_prompt_content_list_item_bullet_color, theme) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index 7b8cb829e03f..04dc7a8da9f3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -31,6 +31,7 @@ import android.view.View import android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO import android.view.accessibility.AccessibilityManager import android.widget.Button +import android.widget.ScrollView import android.widget.TextView import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle @@ -94,6 +95,8 @@ object BiometricViewBinder { val titleView = view.requireViewById<TextView>(R.id.title) val subtitleView = view.requireViewById<TextView>(R.id.subtitle) val descriptionView = view.requireViewById<TextView>(R.id.description) + val customizedViewContainer = + view.requireViewById<ScrollView>(R.id.customized_view_container) // set selected to enable marquee unless a screen reader is enabled titleView.isSelected = @@ -150,8 +153,13 @@ object BiometricViewBinder { } titleView.text = viewModel.title.first() - descriptionView.text = viewModel.description.first() subtitleView.text = viewModel.subtitle.first() + descriptionView.text = viewModel.description.first() + BiometricCustomizedViewBinder.bind( + customizedViewContainer, + view.requireViewById(R.id.space_above_content), + viewModel + ) // set button listeners negativeButton.setOnClickListener { legacyCallback.onButtonNegative() } @@ -178,12 +186,14 @@ object BiometricViewBinder { titleView, subtitleView, descriptionView, + customizedViewContainer, ), viewsToFadeInOnSizeChange = listOf( titleView, subtitleView, descriptionView, + customizedViewContainer, indicatorMessageView, negativeButton, cancelButton, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index 1a7b6c974d0c..c3bbaedb2670 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -55,7 +55,7 @@ object BiometricViewSizeBinder { fun bind( view: BiometricPromptLayout, viewModel: PromptViewModel, - viewsToHideWhenSmall: List<TextView>, + viewsToHideWhenSmall: List<View>, viewsToFadeInOnSizeChange: List<View>, panelViewController: AuthPanelController, jankListener: BiometricJankListener, @@ -110,7 +110,7 @@ object BiometricViewSizeBinder { // prepare for animated size transitions for (v in viewsToHideWhenSmall) { - v.showTextOrHide(forceHide = size.isSmall) + v.showContentOrHide(forceHide = size.isSmall) } if (currentSize == null && size.isSmall) { iconHolderView.alpha = 0f @@ -119,6 +119,10 @@ object BiometricViewSizeBinder { viewsToFadeInOnSizeChange.forEach { it.alpha = 0f } } + // TODO(b/302735104): Fix wrong height due to the delay of + // PromptContentView. addOnLayoutChangeListener() will cause crash when + // showing credential view, since |PromptIconViewModel| won't release the + // flow. // propagate size changes to legacy panel controller and animate transitions view.doOnLayout { val width = view.measuredWidth @@ -228,8 +232,9 @@ private fun View.isLandscape(): Boolean { return r == Surface.ROTATION_90 || r == Surface.ROTATION_270 } -private fun TextView.showTextOrHide(forceHide: Boolean = false) { - visibility = if (forceHide || text.isBlank()) View.GONE else View.VISIBLE +private fun View.showContentOrHide(forceHide: Boolean = false) { + val isTextViewWithBlankText = this is TextView && this.text.isBlank() + visibility = if (forceHide || isTextViewWithBlankText) View.GONE else View.VISIBLE } private fun View.asVerticalAnimator( diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index d899827ebb2e..1c789283ec70 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -13,11 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.systemui.biometrics.ui.viewmodel import android.content.Context import android.graphics.Rect import android.hardware.biometrics.BiometricPrompt +import android.hardware.biometrics.PromptContentView import android.util.Log import android.view.HapticFeedbackConstants import android.view.MotionEvent @@ -239,9 +241,20 @@ constructor( val subtitle: Flow<String> = promptSelectorInteractor.prompt.map { it?.subtitle ?: "" }.distinctUntilChanged() - /** Description for the prompt. */ - val description: Flow<String> = + /** Custom content view for the prompt. */ + val contentView: Flow<PromptContentView?> = + promptSelectorInteractor.prompt.map { it?.contentView }.distinctUntilChanged() + + private val originalDescription = promptSelectorInteractor.prompt.map { it?.description ?: "" }.distinctUntilChanged() + /** + * Description for the prompt. Description view and contentView is mutually exclusive. Pass + * description down only when contentView is null. + */ + val description: Flow<String> = + combine(contentView, originalDescription) { contentView, description -> + if (contentView == null) description else "" + } /** If the indicator (help, error) message should be shown. */ val isIndicatorMessageVisible: Flow<Boolean> = diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt index c2a1d8fe26c3..d0ff1858a1c9 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/data/repository/KeyguardBouncerRepository.kt @@ -20,6 +20,7 @@ import android.os.Build import android.util.Log import com.android.systemui.biometrics.shared.SideFpsControllerRefactor import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN +import com.android.systemui.bouncer.shared.model.BouncerDismissActionModel import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -90,6 +91,9 @@ interface KeyguardBouncerRepository { val alternateBouncerUIAvailable: StateFlow<Boolean> val sideFpsShowing: StateFlow<Boolean> + /** Action that should be run right after the bouncer is dismissed. */ + var bouncerDismissActionModel: BouncerDismissActionModel? + var lastAlternateBouncerVisibleTime: Long fun setPrimaryScrimmed(isScrimmed: Boolean) @@ -134,6 +138,8 @@ constructor( @Application private val applicationScope: CoroutineScope, @BouncerTableLog private val buffer: TableLogBuffer, ) : KeyguardBouncerRepository { + override var bouncerDismissActionModel: BouncerDismissActionModel? = null + /** Values associated with the PrimaryBouncer (pin/pattern/password) input. */ private val _primaryBouncerShow = MutableStateFlow(false) override val primaryBouncerShow = _primaryBouncerShow.asStateFlow() diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt index 654fa220d491..8c87b0c78ea7 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractor.kt @@ -28,10 +28,12 @@ import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.DejankUtils +import com.android.systemui.Flags import com.android.systemui.biometrics.shared.SideFpsControllerRefactor import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_HIDDEN +import com.android.systemui.bouncer.shared.model.BouncerDismissActionModel import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector @@ -154,12 +156,12 @@ constructor( /** Show the bouncer if necessary and set the relevant states. */ @JvmOverloads fun show(isScrimmed: Boolean) { - if (primaryBouncerView.delegate == null) { + if (primaryBouncerView.delegate == null && !Flags.composeBouncer()) { Log.d( TAG, "PrimaryBouncerInteractor#show is being called before the " + - "primaryBouncerDelegate is set. Let's exit early so we don't set the wrong " + - "primaryBouncer state." + "primaryBouncerDelegate is set. Let's exit early so we don't " + + "set the wrong primaryBouncer state." ) return } @@ -272,15 +274,24 @@ constructor( repository.setShowMessage(BouncerShowMessageModel(message, colorStateList)) } + val bouncerDismissAction: BouncerDismissActionModel? + get() = repository.bouncerDismissActionModel + /** * Sets actions to the bouncer based on how the bouncer is dismissed. If the bouncer is - * unlocked, we will run the onDismissAction. If the bouncer is existed before unlocking, we - * call cancelAction. + * unlocked, we will run the onDismissAction. If the bouncer is exited before unlocking, we call + * cancelAction. */ fun setDismissAction( onDismissAction: ActivityStarter.OnDismissAction?, cancelAction: Runnable? ) { + repository.bouncerDismissActionModel = + if (onDismissAction != null && cancelAction != null) { + BouncerDismissActionModel(onDismissAction, cancelAction) + } else { + null + } primaryBouncerView.delegate?.setDismissAction(onDismissAction, cancelAction) } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerDismissActionModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerDismissActionModel.kt new file mode 100644 index 000000000000..02b444f5a69f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bouncer/shared/model/BouncerDismissActionModel.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 The Android Open 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.bouncer.shared.model + +import com.android.systemui.plugins.ActivityStarter + +/** Represents the action that needs to be performed after bouncer is dismissed. */ +data class BouncerDismissActionModel( + /** If the bouncer is unlocked, [onDismissAction] will be run. */ + val onDismissAction: ActivityStarter.OnDismissAction?, + /** If the bouncer is exited before unlocking, [onCancel] will be invoked. */ + val onCancel: Runnable? +) diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt new file mode 100644 index 000000000000..5defe4754073 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open 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.bouncer.ui + +import android.app.AlertDialog + +/** Factory to create alert dialogs for use in bouncer component. */ +interface BouncerDialogFactory { + operator fun invoke(): AlertDialog +} diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt index 7f3b794e2ac3..f3903ded7cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerViewModule.kt @@ -16,9 +16,15 @@ package com.android.systemui.bouncer.ui +import android.app.AlertDialog +import android.content.Context import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModelModule +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.statusbar.phone.SystemUIDialog import dagger.Binds import dagger.Module +import dagger.Provides @Module( includes = @@ -29,4 +35,17 @@ import dagger.Module interface BouncerViewModule { /** Binds BouncerView to BouncerViewImpl and makes it injectable. */ @Binds fun bindBouncerView(bouncerViewImpl: BouncerViewImpl): BouncerView + + companion object { + + @Provides + @SysUISingleton + fun bouncerDialogFactory(@Application context: Context): BouncerDialogFactory { + return object : BouncerDialogFactory { + override fun invoke(): AlertDialog { + return SystemUIDialog(context) + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt new file mode 100644 index 000000000000..dd253a8f6eff --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/BouncerViewBinder.kt @@ -0,0 +1,89 @@ +package com.android.systemui.bouncer.ui.binder + +import android.view.ViewGroup +import com.android.keyguard.KeyguardMessageAreaController +import com.android.keyguard.ViewMediatorCallback +import com.android.keyguard.dagger.KeyguardBouncerComponent +import com.android.systemui.Flags +import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor +import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.bouncer.ui.BouncerDialogFactory +import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel +import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel +import com.android.systemui.compose.ComposeFacade +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.flags.Flags.COMPOSE_BOUNCER_ENABLED +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel +import com.android.systemui.log.BouncerLogger +import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import dagger.Lazy +import javax.inject.Inject + +/** Helper data class that allows to lazy load all the dependencies of the legacy bouncer. */ +@SysUISingleton +data class LegacyBouncerDependencies +@Inject +constructor( + val viewModel: KeyguardBouncerViewModel, + val primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel, + val componentFactory: KeyguardBouncerComponent.Factory, + val messageAreaControllerFactory: KeyguardMessageAreaController.Factory, + val bouncerMessageInteractor: BouncerMessageInteractor, + val bouncerLogger: BouncerLogger, + val selectedUserInteractor: SelectedUserInteractor, +) + +/** Helper data class that allows to lazy load all the dependencies of the compose based bouncer. */ +@SysUISingleton +data class ComposeBouncerDependencies +@Inject +constructor( + val legacyInteractor: PrimaryBouncerInteractor, + val viewModel: BouncerViewModel, + val dialogFactory: BouncerDialogFactory, + val authenticationInteractor: AuthenticationInteractor, + val viewMediatorCallback: ViewMediatorCallback?, + val selectedUserInteractor: SelectedUserInteractor, +) + +/** + * Toggles between the compose and non compose version of the bouncer, instantiating only the + * dependencies required for each. + */ +@SysUISingleton +class BouncerViewBinder +@Inject +constructor( + private val legacyBouncerDependencies: Lazy<LegacyBouncerDependencies>, + private val composeBouncerDependencies: Lazy<ComposeBouncerDependencies>, +) { + fun bind(view: ViewGroup) { + if ( + ComposeFacade.isComposeAvailable() && Flags.composeBouncer() && COMPOSE_BOUNCER_ENABLED + ) { + val deps = composeBouncerDependencies.get() + ComposeBouncerViewBinder.bind( + view, + deps.legacyInteractor, + deps.viewModel, + deps.dialogFactory, + deps.authenticationInteractor, + deps.selectedUserInteractor, + deps.viewMediatorCallback, + ) + } else { + val deps = legacyBouncerDependencies.get() + KeyguardBouncerViewBinder.bind( + view, + deps.viewModel, + deps.primaryBouncerToGoneTransitionViewModel, + deps.componentFactory, + deps.messageAreaControllerFactory, + deps.bouncerMessageInteractor, + deps.bouncerLogger, + deps.selectedUserInteractor, + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt new file mode 100644 index 000000000000..7b053956091e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/binder/ComposeBouncerViewBinder.kt @@ -0,0 +1,75 @@ +package com.android.systemui.bouncer.ui.binder + +import android.view.ViewGroup +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.repeatOnLifecycle +import com.android.keyguard.ViewMediatorCallback +import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor +import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor +import com.android.systemui.bouncer.ui.BouncerDialogFactory +import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel +import com.android.systemui.compose.ComposeFacade +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.user.domain.interactor.SelectedUserInteractor +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +/** View binder responsible for binding the compose version of the bouncer. */ +object ComposeBouncerViewBinder { + fun bind( + view: ViewGroup, + legacyInteractor: PrimaryBouncerInteractor, + viewModel: BouncerViewModel, + dialogFactory: BouncerDialogFactory, + authenticationInteractor: AuthenticationInteractor, + selectedUserInteractor: SelectedUserInteractor, + viewMediatorCallback: ViewMediatorCallback?, + ) { + view.addView( + ComposeFacade.createBouncer( + view.context, + viewModel, + dialogFactory, + ) + ) + view.repeatWhenAttached { + repeatOnLifecycle(Lifecycle.State.CREATED) { + launch { + legacyInteractor.isShowing.collectLatest { bouncerShowing -> + view.isVisible = bouncerShowing + } + } + + launch { + authenticationInteractor.onAuthenticationResult.collectLatest { + authenticationSucceeded -> + if (authenticationSucceeded) { + // Some dismiss actions require that keyguard be dismissed right away or + // deferred until something else later on dismisses keyguard (eg. end of + // a hide animation). + val deferKeyguardDone = + legacyInteractor.bouncerDismissAction?.onDismissAction?.onDismiss() + legacyInteractor.setDismissAction(null, null) + + viewMediatorCallback?.let { + val selectedUserId = selectedUserInteractor.getSelectedUserId() + if (deferKeyguardDone == true) { + it.keyguardDonePending(selectedUserId) + } else { + it.keyguardDone(selectedUserId) + } + } + } + } + } + launch { + legacyInteractor.startingDisappearAnimation.collectLatest { + it.run() + legacyInteractor.hide() + } + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 24d4c6c4c397..9fa4cd6c7985 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -37,6 +37,8 @@ import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map @@ -77,6 +79,29 @@ constructor( communalRepository.setTransitionState(transitionState) } + /** Returns a flow that tracks the progress of transitions to the given scene from 0-1. */ + fun transitionProgressToScene(targetScene: CommunalSceneKey) = + transitionState + .flatMapLatest { state -> + when (state) { + is ObservableCommunalTransitionState.Idle -> + flowOf(CommunalTransitionProgress.Idle(state.scene)) + is ObservableCommunalTransitionState.Transition -> + if (state.toScene == targetScene) { + state.progress.map { + CommunalTransitionProgress.Transition( + // Clamp the progress values between 0 and 1 as actual progress + // values can be higher than 0 or lower than 1 due to a fling. + progress = it.coerceIn(0.0f, 1.0f) + ) + } + } else { + flowOf(CommunalTransitionProgress.OtherTransition) + } + } + } + .distinctUntilChanged() + /** * Flow that emits a boolean if the communal UI is showing, ie. the [desiredScene] is the * [CommunalSceneKey.Communal]. @@ -232,3 +257,17 @@ constructor( } } } + +/** Simplified transition progress data class for tracking a single transition between scenes. */ +sealed class CommunalTransitionProgress { + /** No transition/animation is currently running. */ + data class Idle(val scene: CommunalSceneKey) : CommunalTransitionProgress() + + /** There is a transition animating to the expected scene. */ + data class Transition( + val progress: Float, + ) : CommunalTransitionProgress() + + /** There is a transition animating to a scene other than the expected scene. */ + data object OtherTransition : CommunalTransitionProgress() +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt new file mode 100644 index 000000000000..889023e8dab6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/log/CommunalLoggerStartable.kt @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2024 The Android Open 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.communal.log + +import com.android.internal.logging.UiEventLogger +import com.android.systemui.CoreStartable +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.shared.log.CommunalUiEvent +import com.android.systemui.communal.shared.model.CommunalSceneKey +import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.util.kotlin.pairwise +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.drop +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onEach + +/** A [CoreStartable] responsible for logging metrics for the communal hub. */ +@SysUISingleton +class CommunalLoggerStartable +@Inject +constructor( + @Background private val backgroundScope: CoroutineScope, + private val communalInteractor: CommunalInteractor, + private val uiEventLogger: UiEventLogger, +) : CoreStartable { + + override fun start() { + communalInteractor.transitionState + .map { state -> + when { + state.isOnCommunal() -> CommunalUiEvent.COMMUNAL_HUB_SHOWN + state.isNotOnCommunal() -> CommunalUiEvent.COMMUNAL_HUB_GONE + else -> null + } + } + .filterNotNull() + .distinctUntilChanged() + // Drop the default value. + .drop(1) + .onEach { uiEvent -> uiEventLogger.log(uiEvent) } + .launchIn(backgroundScope) + + communalInteractor.transitionState + .pairwise() + .map { (old, new) -> + when { + new.isOnCommunal() && old.isSwipingToCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_FINISH + new.isOnCommunal() && old.isSwipingFromCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_CANCEL + new.isNotOnCommunal() && old.isSwipingFromCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_FINISH + new.isNotOnCommunal() && old.isSwipingToCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_CANCEL + new.isSwipingToCommunal() && old.isNotOnCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_ENTER_START + new.isSwipingFromCommunal() && old.isOnCommunal() -> + CommunalUiEvent.COMMUNAL_HUB_SWIPE_TO_EXIT_START + else -> null + } + } + .filterNotNull() + .distinctUntilChanged() + .onEach { uiEvent -> uiEventLogger.log(uiEvent) } + .launchIn(backgroundScope) + } +} + +/** Whether currently in communal scene. */ +private fun ObservableCommunalTransitionState.isOnCommunal(): Boolean { + return this is ObservableCommunalTransitionState.Idle && scene == CommunalSceneKey.Communal +} + +/** Whether currently in a scene other than communal. */ +private fun ObservableCommunalTransitionState.isNotOnCommunal(): Boolean { + return this is ObservableCommunalTransitionState.Idle && scene != CommunalSceneKey.Communal +} + +/** Whether currently transitioning from another scene to communal. */ +private fun ObservableCommunalTransitionState.isSwipingToCommunal(): Boolean { + return this is ObservableCommunalTransitionState.Transition && + toScene == CommunalSceneKey.Communal && + isInitiatedByUserInput +} + +/** Whether currently transitioning from communal to another scene. */ +private fun ObservableCommunalTransitionState.isSwipingFromCommunal(): Boolean { + return this is ObservableCommunalTransitionState.Transition && + fromScene == CommunalSceneKey.Communal && + isInitiatedByUserInput +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalUiEvent.kt b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalUiEvent.kt index e167f3e263fe..b64c1955b43d 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalUiEvent.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/shared/log/CommunalUiEvent.kt @@ -22,8 +22,6 @@ import com.android.internal.logging.UiEventLogger.UiEventEnum /** UI events for the Communal Hub. */ enum class CommunalUiEvent(private val id: Int) : UiEventEnum { @UiEvent(doc = "Communal Hub is fully shown") COMMUNAL_HUB_SHOWN(1566), - @UiEvent(doc = "Communal Hub starts entering") COMMUNAL_HUB_ENTERING(1575), - @UiEvent(doc = "Communal Hub starts exiting") COMMUNAL_HUB_EXITING(1576), @UiEvent(doc = "Communal Hub is fully gone") COMMUNAL_HUB_GONE(1577), @UiEvent(doc = "Communal Hub times out") COMMUNAL_HUB_TIMEOUT(1578), @UiEvent(doc = "The visible content in the Communal Hub is fully loaded and rendered") diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index 4cb83a3b51dc..84708a49f469 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -17,25 +17,19 @@ package com.android.systemui.communal.ui.viewmodel import android.content.ComponentName -import android.os.PowerManager -import android.os.SystemClock -import android.view.MotionEvent import android.widget.RemoteViews import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState import com.android.systemui.media.controls.ui.MediaHost -import com.android.systemui.shade.ShadeViewController -import javax.inject.Provider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOf /** The base view model for the communal hub. */ abstract class BaseCommunalViewModel( private val communalInteractor: CommunalInteractor, - private val shadeViewController: Provider<ShadeViewController>, - private val powerManager: PowerManager, val mediaHost: MediaHost, ) { val isKeyguardVisible: Flow<Boolean> = communalInteractor.isKeyguardVisible @@ -70,32 +64,18 @@ abstract class BaseCommunalViewModel( return true } - // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block - // touches anymore. - /** Called when a touch is received outside the edge swipe area when hub mode is closed. */ - fun onOuterTouch(motionEvent: MotionEvent) { - // Forward the touch to the shade so that basic gestures like swipe up/down for - // shade/bouncer work. - shadeViewController.get().handleExternalTouch(motionEvent) - } - - // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block - // touches anymore. - /** Called to refresh the screen timeout when a user touch is received. */ - fun onUserActivity() { - powerManager.userActivity( - SystemClock.uptimeMillis(), - PowerManager.USER_ACTIVITY_EVENT_TOUCH, - 0 - ) - } - /** A list of all the communal content to be displayed in the communal hub. */ abstract val communalContent: Flow<List<CommunalContentModel>> /** Whether in edit mode for the communal hub. */ open val isEditMode = false + /** Whether the popup message triggered by dismissing the CTA tile is showing. */ + open val isPopupOnDismissCtaShowing: Flow<Boolean> = flowOf(false) + + /** Hide the popup message triggered by dismissing the CTA tile. */ + open fun onHidePopupAfterDismissCta() {} + /** Called as the UI requests deleting a widget. */ open fun onDeleteWidget(id: Int) {} diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt index 0cbf3f1312e2..7faf653cc177 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt @@ -23,7 +23,6 @@ import android.app.ActivityOptions import android.appwidget.AppWidgetHost import android.content.ActivityNotFoundException import android.content.ComponentName -import android.os.PowerManager import android.widget.RemoteViews import com.android.internal.logging.UiEventLogger import com.android.systemui.communal.domain.interactor.CommunalInteractor @@ -32,11 +31,9 @@ import com.android.systemui.communal.shared.log.CommunalUiEvent import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.controls.ui.MediaHost import com.android.systemui.media.dagger.MediaModule -import com.android.systemui.shade.ShadeViewController import com.android.systemui.util.nullableAtomicReference import javax.inject.Inject import javax.inject.Named -import javax.inject.Provider import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -49,11 +46,9 @@ class CommunalEditModeViewModel constructor( private val communalInteractor: CommunalInteractor, private val appWidgetHost: AppWidgetHost, - shadeViewController: Provider<ShadeViewController>, - powerManager: PowerManager, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, private val uiEventLogger: UiEventLogger, -) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) { +) : BaseCommunalViewModel(communalInteractor, mediaHost) { private companion object { private const val KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle" diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 066e897cdfdb..09c18ed0c8de 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -16,37 +16,42 @@ package com.android.systemui.communal.ui.viewmodel -import android.os.PowerManager import android.widget.RemoteViews import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.widgets.WidgetInteractionHandler import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.media.controls.ui.MediaHierarchyManager import com.android.systemui.media.controls.ui.MediaHost +import com.android.systemui.media.controls.ui.MediaHostState import com.android.systemui.media.dagger.MediaModule -import com.android.systemui.shade.ShadeViewController import javax.inject.Inject import javax.inject.Named -import javax.inject.Provider +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch /** The default view model used for showing the communal hub. */ @SysUISingleton class CommunalViewModel @Inject constructor( + @Application private val scope: CoroutineScope, private val communalInteractor: CommunalInteractor, private val interactionHandler: WidgetInteractionHandler, tutorialInteractor: CommunalTutorialInteractor, - shadeViewController: Provider<ShadeViewController>, - powerManager: PowerManager, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, -) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) { +) : BaseCommunalViewModel(communalInteractor, mediaHost) { @OptIn(ExperimentalCoroutinesApi::class) override val communalContent: Flow<List<CommunalContentModel>> = tutorialInteractor.isTutorialAvailable.flatMapLatest { isTutorialMode -> @@ -63,9 +68,56 @@ constructor( } } + private val _isPopupOnDismissCtaShowing: MutableStateFlow<Boolean> = MutableStateFlow(false) + override val isPopupOnDismissCtaShowing: Flow<Boolean> = + _isPopupOnDismissCtaShowing.asStateFlow() + + init { + // Initialize our media host for the UMO. This only needs to happen once and must be done + // before the MediaHierarchyManager attempts to move the UMO to the hub. + with(mediaHost) { + expansion = MediaHostState.EXPANDED + showsOnlyActiveMedia = false + falsingProtectionNeeded = false + init(MediaHierarchyManager.LOCATION_COMMUNAL_HUB) + } + } + override fun onOpenWidgetEditor() = communalInteractor.showWidgetEditor() - override fun onDismissCtaTile() = communalInteractor.dismissCtaTile() + override fun onDismissCtaTile() { + communalInteractor.dismissCtaTile() + setPopupOnDismissCtaVisibility(true) + schedulePopupHiding() + } override fun getInteractionHandler(): RemoteViews.InteractionHandler = interactionHandler + + override fun onHidePopupAfterDismissCta() { + cancelDelayedPopupHiding() + setPopupOnDismissCtaVisibility(false) + } + + private fun setPopupOnDismissCtaVisibility(isVisible: Boolean) { + _isPopupOnDismissCtaShowing.value = isVisible + } + + private var delayedHidePopupJob: Job? = null + private fun schedulePopupHiding() { + cancelDelayedPopupHiding() + delayedHidePopupJob = + scope.launch { + delay(POPUP_AUTO_HIDE_TIMEOUT_MS) + onHidePopupAfterDismissCta() + } + } + + private fun cancelDelayedPopupHiding() { + delayedHidePopupJob?.cancel() + delayedHidePopupJob = null + } + + companion object { + const val POPUP_AUTO_HIDE_TIMEOUT_MS = 12000L + } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt index bfc6f2b14acd..380ed61a556d 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt @@ -30,6 +30,8 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import com.android.internal.logging.UiEventLogger +import com.android.systemui.communal.shared.log.CommunalUiEvent import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel import com.android.systemui.compose.ComposeFacade.setCommunalEditWidgetActivityContent import javax.inject.Inject @@ -41,6 +43,7 @@ class EditWidgetsActivity constructor( private val communalViewModel: CommunalEditModeViewModel, private var windowManagerService: IWindowManager? = null, + private val uiEventLogger: UiEventLogger, ) : ComponentActivity() { companion object { private const val EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag" @@ -54,6 +57,8 @@ constructor( registerForActivityResult(StartActivityForResult()) { result -> when (result.resultCode) { RESULT_OK -> { + uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_WIDGET_PICKER_SHOWN) + result.data?.let { intent -> val isPendingWidgetDrag = intent.getBooleanExtra(EXTRA_IS_PENDING_WIDGET_DRAG, false) @@ -144,4 +149,16 @@ constructor( communalViewModel.setConfigurationResult(resultCode) } } + + override fun onStart() { + super.onStart() + + uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_EDIT_MODE_SHOWN) + } + + override fun onStop() { + super.onStop() + + uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_EDIT_MODE_GONE) + } } diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt index 3a927396527c..acbdecc5d514 100644 --- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt +++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt @@ -22,6 +22,8 @@ import android.view.View import android.view.WindowInsets import androidx.activity.ComponentActivity import androidx.lifecycle.LifecycleOwner +import com.android.systemui.bouncer.ui.BouncerDialogFactory +import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel import com.android.systemui.people.ui.viewmodel.PeopleViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel @@ -88,6 +90,13 @@ interface BaseComposeFacade { viewModel: BaseCommunalViewModel, ): View + /** Create a [View] to represent the [BouncerViewModel]. */ + fun createBouncer( + context: Context, + viewModel: BouncerViewModel, + dialogFactory: BouncerDialogFactory, + ): View + /** Creates a container that hosts the communal UI and handles gesture transitions. */ fun createCommunalContainer(context: Context, viewModel: BaseCommunalViewModel): View } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 87a736d926b5..8d82b552fc1e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -24,6 +24,7 @@ import com.android.systemui.accessibility.Magnification import com.android.systemui.back.domain.interactor.BackActionInteractor import com.android.systemui.biometrics.BiometricNotificationService import com.android.systemui.clipboardoverlay.ClipboardListener +import com.android.systemui.communal.log.CommunalLoggerStartable import com.android.systemui.controls.dagger.StartControlsStartableModule import com.android.systemui.dagger.qualifiers.PerUser import com.android.systemui.dreams.AssistantAttentionMonitor @@ -318,4 +319,9 @@ abstract class SystemUICoreStartableModule { @IntoMap @ClassKey(KeyguardDismissBinder::class) abstract fun bindKeyguardDismissBinder(impl: KeyguardDismissBinder): CoreStartable + + @Binds + @IntoMap + @ClassKey(CommunalLoggerStartable::class) + abstract fun bindCommunalLoggerStartable(impl: CommunalLoggerStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java index 4e4b79c5cfa2..7f3b5eba96c6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/BouncerSwipeTouchHandler.java @@ -155,12 +155,12 @@ public class BouncerSwipeTouchHandler implements DreamTouchHandler { return true; } - // Don't set expansion if the user doesn't have a pin/password set so that no - // animations are played we're not transitioning to the bouncer. - if (!mLockPatternUtils.isSecure(mUserTracker.getUserId())) { - // Return false so the gesture is not consumed, allowing the dream to wake - // if it wants instead of doing nothing. - return false; + // If scrolling up and keyguard is not locked, dismiss the dream since there's + // no bouncer to show. + if (e1.getY() > e2.getY() + && !mLockPatternUtils.isSecure(mUserTracker.getUserId())) { + mCentralSurfaces.get().awakenDreams(); + return true; } // For consistency, we adopt the expansion definition found in the diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 699532cbfca3..846736c04d98 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -122,11 +122,6 @@ object Flags { val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag("new_unlock_swipe_animation") val CHARGING_RIPPLE = resourceBooleanFlag(R.bool.flag_charging_ripple, "charging_ripple") - // TODO(b/254512281): Tracking Bug - @JvmField - val BOUNCER_USER_SWITCHER = - resourceBooleanFlag(R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher") - // TODO(b/254512676): Tracking Bug @JvmField val LOCKSCREEN_CUSTOM_CLOCKS = @@ -353,12 +348,6 @@ object Flags { // TODO(b/254512673): Tracking Bug @JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag("dream_media_tap_to_open") - // TODO(b/254513168): Tracking Bug - @JvmField val UMO_SURFACE_RIPPLE = releasedFlag("umo_surface_ripple") - - // TODO(b/261734857): Tracking Bug - @JvmField val UMO_TURBULENCE_NOISE = releasedFlag("umo_turbulence_noise") - // TODO(b/263272731): Tracking Bug val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag("media_ttt_receiver_success_ripple") @@ -377,9 +366,6 @@ object Flags { // 1000 - dock val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging") - // TODO(b/254512758): Tracking Bug - @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag("rounded_box_ripple") - // TODO(b/273509374): Tracking Bug @JvmField val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS = @@ -490,6 +476,13 @@ object Flags { // TODO(b/283300105): Tracking Bug @JvmField val SCENE_CONTAINER_ENABLED = false + /** + * Whether the compose bouncer is enabled. This ensures ProGuard can + * remove unused code from our APK at compile time. + */ + // TODO(b/280877228): Tracking Bug + @JvmField val COMPOSE_BOUNCER_ENABLED = false + // 1900 @JvmField val NOTE_TASKS = releasedFlag("keycode_flag") diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index a34730e2d71f..5cebd96249b6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -1486,6 +1486,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mOrderUnlockAndWake = context.getResources().getBoolean( com.android.internal.R.bool.config_orderUnlockAndWake); + + mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); + mShowKeyguardWakeLock.setReferenceCounted(false); } public void userActivity() { @@ -1493,9 +1496,6 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } private void setupLocked() { - mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard"); - mShowKeyguardWakeLock.setReferenceCounted(false); - IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SHUTDOWN); mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt index cb0f18630324..42f14f1eb317 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt @@ -140,8 +140,9 @@ constructor( override val revealAmount: Flow<Float> = callbackFlow { val updateListener = Animator.AnimatorUpdateListener { - val value = (it as ValueAnimator).animatedValue - trySend(value as Float) + val value = (it as ValueAnimator).animatedValue as Float + trySend(value) + if (value <= 0.0f || value >= 1.0f) { scrimLogger.d(TAG, "revealAmount", value) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt index ecf78d550a3f..b1a2297526ce 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt @@ -30,6 +30,7 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map @@ -82,10 +83,11 @@ constructor( */ val showIndicatorForDeviceEntry: Flow<Boolean> = combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) { - showForPrimaryBouncer, - showForAlternateBouncer -> - showForPrimaryBouncer || showForAlternateBouncer - } + showForPrimaryBouncer, + showForAlternateBouncer -> + showForPrimaryBouncer || showForAlternateBouncer + } + .distinctUntilChanged() private fun shouldShowIndicatorForPrimaryBouncer(): Boolean { val sfpsEnabled: Boolean = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt index 52f2759fe63d..7b1466cd1fc9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt @@ -18,7 +18,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor @@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.sample import com.android.wm.shell.animation.Interpolators import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.combine @@ -39,13 +41,18 @@ class FromAlternateBouncerTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val powerInteractor: PowerInteractor, ) : TransitionInteractor( fromState = KeyguardState.ALTERNATE_BOUNCER, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -65,7 +72,7 @@ constructor( .sample( combine( keyguardInteractor.primaryBouncerShowing, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, powerInteractor.isAwake, keyguardInteractor.isAodAvailable, ::toQuad @@ -102,20 +109,19 @@ constructor( private fun listenForAlternateBouncerToGone() { scope.launch { - keyguardInteractor.isKeyguardGoingAway - .sample(transitionInteractor.finishedKeyguardState, ::Pair) - .collect { (isKeyguardGoingAway, keyguardState) -> - if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) { - startTransitionTo(KeyguardState.GONE) - } + keyguardInteractor.isKeyguardGoingAway.sample(finishedKeyguardState, ::Pair).collect { + (isKeyguardGoingAway, keyguardState) -> + if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) { + startTransitionTo(KeyguardState.GONE) } + } } } private fun listenForAlternateBouncerToPrimaryBouncer() { scope.launch { keyguardInteractor.primaryBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isPrimaryBouncerShowing, startedKeyguardState) -> if ( isPrimaryBouncerShowing && @@ -139,8 +145,10 @@ constructor( } companion object { + const val TAG = "FromAlternateBouncerTransitionInteractor" val TRANSITION_DURATION_MS = 300.milliseconds val TO_GONE_DURATION = 500.milliseconds val TO_AOD_DURATION = TRANSITION_DURATION_MS + val TO_PRIMARY_BOUNCER_DURATION = TRANSITION_DURATION_MS } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt index 858440185568..fedd63be1454 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock import com.android.systemui.keyguard.shared.model.DozeStateModel @@ -29,6 +30,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -38,12 +40,17 @@ class FromAodTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, ) : TransitionInteractor( fromState = KeyguardState.AOD, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -58,7 +65,7 @@ constructor( .dozeTransitionTo(DozeStateModel.FINISH) .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isKeyguardOccluded, ::Pair ), @@ -77,7 +84,6 @@ constructor( } else { TransitionModeOnCanceled.LAST_VALUE } - startTransitionTo( toState = toState, modeOnCanceled = modeOnCanceled, @@ -89,16 +95,13 @@ constructor( private fun listenForAodToGone() { scope.launch { - keyguardInteractor.biometricUnlockState - .sample(transitionInteractor.finishedKeyguardState, ::Pair) - .collect { pair -> - val (biometricUnlockState, keyguardState) = pair - if ( - keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState) - ) { - startTransitionTo(KeyguardState.GONE) - } + keyguardInteractor.biometricUnlockState.sample(finishedKeyguardState, ::Pair).collect { + pair -> + val (biometricUnlockState, keyguardState) = pair + if (keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)) { + startTransitionTo(KeyguardState.GONE) } + } } } override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { @@ -113,6 +116,7 @@ constructor( } companion object { + const val TAG = "FromAodTransitionInteractor" private val DEFAULT_DURATION = 500.milliseconds val TO_LOCKSCREEN_DURATION = 500.milliseconds val TO_GONE_DURATION = DEFAULT_DURATION diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index eca7088c079a..fcb7698c9bf5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock import com.android.systemui.keyguard.shared.model.KeyguardState @@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -37,13 +39,18 @@ class FromDozingTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val powerInteractor: PowerInteractor, ) : TransitionInteractor( fromState = KeyguardState.DOZING, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -57,7 +64,7 @@ constructor( powerInteractor.isAwake .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isKeyguardOccluded, ::Pair ), @@ -76,7 +83,7 @@ constructor( private fun listenForDozingToGone() { scope.launch { keyguardInteractor.biometricUnlockState - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (biometricUnlockState, lastStartedTransition) -> if ( lastStartedTransition.to == KeyguardState.DOZING && @@ -96,6 +103,7 @@ constructor( } companion object { + const val TAG = "FromDozingTransitionInteractor" private val DEFAULT_DURATION = 500.milliseconds val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt index dac6ef5e6082..a6cdaa8c6761 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.DozeStateModel @@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.combine @@ -39,12 +41,17 @@ class FromDreamingLockscreenHostedTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, ) : TransitionInteractor( fromState = KeyguardState.DREAMING_LOCKSCREEN_HOSTED, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -64,7 +71,7 @@ constructor( .sample( combine( keyguardInteractor.dozeTransitionModel, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, ::Pair ), ::toTriple @@ -88,7 +95,7 @@ constructor( .sample( combine( keyguardInteractor.isKeyguardOccluded, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, ::Pair, ), ::toTriple @@ -108,7 +115,7 @@ constructor( private fun listenForDreamingLockscreenHostedToPrimaryBouncer() { scope.launch { keyguardInteractor.primaryBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isBouncerShowing, lastStartedTransitionStep) -> if ( isBouncerShowing && @@ -123,7 +130,7 @@ constructor( private fun listenForDreamingLockscreenHostedToGone() { scope.launch { keyguardInteractor.biometricUnlockState - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (biometricUnlockState, lastStartedTransitionStep) -> if ( lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED && @@ -137,11 +144,7 @@ constructor( private fun listenForDreamingLockscreenHostedToDozing() { scope.launch { - combine( - keyguardInteractor.dozeTransitionModel, - transitionInteractor.startedKeyguardTransitionStep, - ::Pair - ) + combine(keyguardInteractor.dozeTransitionModel, startedKeyguardTransitionStep, ::Pair) .collect { (dozeTransitionModel, lastStartedTransitionStep) -> if ( dozeTransitionModel.to == DozeStateModel.DOZE && diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index 7fdcf2f09bc1..13ffd6396cda 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.DozeStateModel @@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -37,12 +39,17 @@ class FromDreamingTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, ) : TransitionInteractor( fromState = KeyguardState.DREAMING, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -66,7 +73,7 @@ constructor( private fun listenForDreamingToOccluded() { scope.launch { combine(keyguardInteractor.isKeyguardOccluded, keyguardInteractor.isDreaming, ::Pair) - .sample(transitionInteractor.startedKeyguardTransitionStep, ::toTriple) + .sample(startedKeyguardTransitionStep, ::toTriple) .collect { (isOccluded, isDreaming, lastStartedTransition) -> if ( isOccluded && @@ -82,7 +89,7 @@ constructor( private fun listenForDreamingToGone() { scope.launch { keyguardInteractor.biometricUnlockState - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (biometricUnlockState, lastStartedTransitionStep) -> if ( lastStartedTransitionStep.to == KeyguardState.DREAMING && @@ -96,11 +103,7 @@ constructor( private fun listenForDreamingToAodOrDozing() { scope.launch { - combine( - keyguardInteractor.dozeTransitionModel, - transitionInteractor.finishedKeyguardState, - ::Pair - ) + combine(keyguardInteractor.dozeTransitionModel, finishedKeyguardState, ::Pair) .collect { (dozeTransitionModel, keyguardState) -> if (keyguardState == KeyguardState.DREAMING) { if (dozeTransitionModel.to == DozeStateModel.DOZE) { @@ -123,6 +126,7 @@ constructor( } companion object { + const val TAG = "FromDreamingTransitionInteractor" private val DEFAULT_DURATION = 500.milliseconds val TO_LOCKSCREEN_DURATION = 1167.milliseconds } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt index 70c2e6d56ca3..48b3d9acfe6a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt @@ -19,23 +19,37 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.Flags +import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher @SysUISingleton class FromGlanceableHubTransitionInteractor @Inject constructor( + private val glanceableHubTransitions: GlanceableHubTransitions, override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, -) : TransitionInteractor(fromState = KeyguardState.GLANCEABLE_HUB) { + transitionInteractor: KeyguardTransitionInteractor, + @Main mainDispatcher: CoroutineDispatcher, + @Background bgDispatcher: CoroutineDispatcher, +) : + TransitionInteractor( + fromState = KeyguardState.GLANCEABLE_HUB, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, + ) { override fun start() { if (!Flags.communalHub()) { return } + listenForHubToLockscreen() } override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { @@ -45,6 +59,18 @@ constructor( } } + /** + * Listens for the glanceable hub transition to lock screen and directly drives the keyguard + * transition. + */ + private fun listenForHubToLockscreen() { + glanceableHubTransitions.listenForLockscreenAndHubTransition( + transitionName = "listenForHubToLockscreen", + transitionOwnerName = TAG, + toScene = CommunalSceneKey.Blank + ) + } + companion object { const val TAG = "FromGlanceableHubTransitionInteractor" val DEFAULT_DURATION = 500.milliseconds diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt index 62a0b0ebc08c..742790eeaedb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled @@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -37,13 +39,18 @@ class FromGoneTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val powerInteractor: PowerInteractor, ) : TransitionInteractor( fromState = KeyguardState.GONE, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -57,7 +64,7 @@ constructor( private fun listenForGoneToLockscreen() { scope.launch { keyguardInteractor.isKeyguardShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isKeyguardShowing, lastStartedStep) -> if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) { startTransitionTo(KeyguardState.LOCKSCREEN) @@ -69,7 +76,7 @@ constructor( private fun listenForGoneToDreamingLockscreenHosted() { scope.launch { keyguardInteractor.isActiveDreamLockscreenHosted - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isActiveDreamLockscreenHosted, lastStartedStep) -> if (isActiveDreamLockscreenHosted && lastStartedStep.to == KeyguardState.GONE) { startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED) @@ -83,7 +90,7 @@ constructor( keyguardInteractor.isAbleToDream .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isActiveDreamLockscreenHosted, ::Pair ), @@ -106,7 +113,7 @@ constructor( powerInteractor.isAsleep .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isAodAvailable, ::Pair ), diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index cecc6537e16e..8b2b45f1bf57 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -18,9 +18,10 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators -import com.android.app.tracing.coroutines.launch +import com.android.systemui.communal.shared.model.CommunalSceneKey import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository @@ -39,28 +40,37 @@ import dagger.Lazy import java.util.UUID import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext @SysUISingleton class FromLockscreenTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val flags: FeatureFlags, private val shadeRepository: ShadeRepository, private val powerInteractor: PowerInteractor, + private val glanceableHubTransitions: GlanceableHubTransitions, inWindowLauncherUnlockAnimationInteractor: Lazy<InWindowLauncherUnlockAnimationInteractor>, ) : TransitionInteractor( fromState = KeyguardState.LOCKSCREEN, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -73,6 +83,7 @@ constructor( listenForLockscreenToPrimaryBouncerDragging() listenForLockscreenToAlternateBouncer() listenForLockscreenTransitionToCamera() + listenForLockscreenToGlanceableHub() } /** @@ -147,12 +158,12 @@ constructor( private fun listenForLockscreenToDreaming() { val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING) - scope.launch("$TAG#listenForLockscreenToDreaming") { + scope.launch { keyguardInteractor.isAbleToDream .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, - transitionInteractor.finishedKeyguardState, + startedKeyguardTransitionStep, + finishedKeyguardState, keyguardInteractor.isActiveDreamLockscreenHosted, ::Triple ), @@ -180,9 +191,9 @@ constructor( } private fun listenForLockscreenToPrimaryBouncer() { - scope.launch("$TAG#listenForLockscreenToPrimaryBouncer") { + scope.launch { keyguardInteractor.primaryBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { pair -> val (isBouncerShowing, lastStartedTransitionStep) = pair if ( @@ -195,9 +206,9 @@ constructor( } private fun listenForLockscreenToAlternateBouncer() { - scope.launch("$TAG#listenForLockscreenToAlternateBouncer") { + scope.launch { keyguardInteractor.alternateBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { pair -> val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair if ( @@ -213,11 +224,11 @@ constructor( /* Starts transitions when manually dragging up the bouncer from the lockscreen. */ private fun listenForLockscreenToPrimaryBouncerDragging() { var transitionId: UUID? = null - scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") { + scope.launch { shadeRepository.legacyShadeExpansion .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.statusBarState, keyguardInteractor.isKeyguardUnlocked, ::Triple @@ -225,72 +236,74 @@ constructor( ::toQuad ) .collect { (shadeExpansion, keyguardState, statusBarState, isKeyguardUnlocked) -> - val id = transitionId - if (id != null) { - if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) { - // An existing `id` means a transition is started, and calls to - // `updateTransition` will control it until FINISHED or CANCELED - var nextState = - if (shadeExpansion == 0f) { - TransitionState.FINISHED - } else if (shadeExpansion == 1f) { - TransitionState.CANCELED - } else { - TransitionState.RUNNING + withContext(mainDispatcher) { + val id = transitionId + if (id != null) { + if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) { + // An existing `id` means a transition is started, and calls to + // `updateTransition` will control it until FINISHED or CANCELED + var nextState = + if (shadeExpansion == 0f) { + TransitionState.FINISHED + } else if (shadeExpansion == 1f) { + TransitionState.CANCELED + } else { + TransitionState.RUNNING + } + transitionRepository.updateTransition( + id, + 1f - shadeExpansion, + nextState, + ) + + if ( + nextState == TransitionState.CANCELED || + nextState == TransitionState.FINISHED + ) { + transitionId = null } - transitionRepository.updateTransition( - id, - 1f - shadeExpansion, - nextState, - ) + // If canceled, just put the state back + // TODO(b/278086361): This logic should happen in + // FromPrimaryBouncerInteractor. + if (nextState == TransitionState.CANCELED) { + transitionRepository.startTransition( + TransitionInfo( + ownerName = name, + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.LOCKSCREEN, + animator = + getDefaultAnimatorForTransitionsToState( + KeyguardState.LOCKSCREEN + ) + .apply { duration = 0 } + ) + ) + } + } + } else { + // TODO (b/251849525): Remove statusbarstate check when that state is + // integrated into KeyguardTransitionRepository if ( - nextState == TransitionState.CANCELED || - nextState == TransitionState.FINISHED + keyguardState.to == KeyguardState.LOCKSCREEN && + shadeRepository.legacyShadeTracking.value && + !isKeyguardUnlocked && + statusBarState == KEYGUARD ) { - transitionId = null - } - - // If canceled, just put the state back - // TODO(b/278086361): This logic should happen in - // FromPrimaryBouncerInteractor. - if (nextState == TransitionState.CANCELED) { - transitionRepository.startTransition( - TransitionInfo( - ownerName = name, - from = KeyguardState.PRIMARY_BOUNCER, - to = KeyguardState.LOCKSCREEN, - animator = - getDefaultAnimatorForTransitionsToState( - KeyguardState.LOCKSCREEN - ) - .apply { duration = 0 } + transitionId = + startTransitionTo( + toState = KeyguardState.PRIMARY_BOUNCER, + animator = null, // transition will be manually controlled ) - ) } } - } else { - // TODO (b/251849525): Remove statusbarstate check when that state is - // integrated into KeyguardTransitionRepository - if ( - keyguardState.to == KeyguardState.LOCKSCREEN && - shadeRepository.legacyShadeTracking.value && - !isKeyguardUnlocked && - statusBarState == KEYGUARD - ) { - transitionId = - startTransitionTo( - toState = KeyguardState.PRIMARY_BOUNCER, - animator = null, // transition will be manually controlled - ) - } } } } } fun dismissKeyguard() { - startTransitionTo(KeyguardState.GONE) + scope.launch { startTransitionTo(KeyguardState.GONE) } } private fun listenForLockscreenToGone() { @@ -298,9 +311,9 @@ constructor( return } - scope.launch("$TAG#listenForLockscreenToGone") { + scope.launch { keyguardInteractor.isKeyguardGoingAway - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { pair -> val (isKeyguardGoingAway, lastStartedStep) = pair if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) { @@ -315,9 +328,9 @@ constructor( return } - scope.launch("$TAG#listenForLockscreenToGoneDragging") { + scope.launch { keyguardInteractor.isKeyguardGoingAway - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { pair -> val (isKeyguardGoingAway, lastStartedStep) = pair if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) { @@ -328,23 +341,22 @@ constructor( } private fun listenForLockscreenToOccluded() { - scope.launch("$TAG#listenForLockscreenToOccluded") { - keyguardInteractor.isKeyguardOccluded - .sample(transitionInteractor.startedKeyguardState, ::Pair) - .collect { (isOccluded, keyguardState) -> - if (isOccluded && keyguardState == KeyguardState.LOCKSCREEN) { - startTransitionTo(KeyguardState.OCCLUDED) - } + scope.launch { + keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect { + (isOccluded, keyguardState) -> + if (isOccluded && keyguardState == KeyguardState.LOCKSCREEN) { + startTransitionTo(KeyguardState.OCCLUDED) } + } } } private fun listenForLockscreenToAodOrDozing() { - scope.launch("$TAG#listenForLockscreenToAodOrDozing") { + scope.launch { powerInteractor.isAsleep .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isAodAvailable, ::Pair ), @@ -372,6 +384,22 @@ constructor( } } + /** + * Listens for transition from glanceable hub back to lock screen and directly drives the + * keyguard transition. + */ + private fun listenForLockscreenToGlanceableHub() { + if (!com.android.systemui.Flags.communalHub()) { + return + } + + glanceableHubTransitions.listenForLockscreenAndHubTransition( + transitionName = "listenForLockscreenToGlanceableHub", + transitionOwnerName = TAG, + toScene = CommunalSceneKey.Communal + ) + } + override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { return ValueAnimator().apply { interpolator = Interpolators.LINEAR @@ -397,5 +425,6 @@ constructor( val TO_AOD_DURATION = 500.milliseconds val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION val TO_GONE_DURATION = DEFAULT_DURATION + val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt index 6a8555cb7f6b..40061f410456 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor @@ -27,6 +28,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -36,13 +38,18 @@ class FromOccludedTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val powerInteractor: PowerInteractor, ) : TransitionInteractor( fromState = KeyguardState.OCCLUDED, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -57,7 +64,7 @@ constructor( private fun listenForOccludedToPrimaryBouncer() { scope.launch { keyguardInteractor.primaryBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isBouncerShowing, lastStartedTransitionStep) -> if ( isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.OCCLUDED @@ -70,13 +77,12 @@ constructor( private fun listenForOccludedToDreaming() { scope.launch { - keyguardInteractor.isAbleToDream - .sample(transitionInteractor.finishedKeyguardState, ::Pair) - .collect { (isAbleToDream, keyguardState) -> - if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) { - startTransitionTo(KeyguardState.DREAMING) - } + keyguardInteractor.isAbleToDream.sample(finishedKeyguardState, ::Pair).collect { + (isAbleToDream, keyguardState) -> + if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) { + startTransitionTo(KeyguardState.DREAMING) } + } } } @@ -86,7 +92,7 @@ constructor( .sample( combine( keyguardInteractor.isKeyguardShowing, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, ::Pair ), ::toTriple @@ -111,7 +117,7 @@ constructor( .sample( combine( keyguardInteractor.isKeyguardShowing, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, ::Pair ), ::toTriple @@ -135,7 +141,7 @@ constructor( powerInteractor.isAsleep .sample( combine( - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isAodAvailable, ::Pair ), @@ -154,7 +160,7 @@ constructor( private fun listenForOccludedToAlternateBouncer() { scope.launch { keyguardInteractor.alternateBouncerShowing - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isAlternateBouncerShowing, lastStartedTransitionStep) -> if ( isAlternateBouncerShowing && @@ -183,6 +189,7 @@ constructor( } companion object { + const val TAG = "FromOccludedTransitionInteractor" private val DEFAULT_DURATION = 500.milliseconds val TO_LOCKSCREEN_DURATION = 933.milliseconds val TO_AOD_DURATION = DEFAULT_DURATION diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index 5f246e181c26..c62055f83517 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.keyguard.KeyguardSecurityModel import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository @@ -35,6 +36,7 @@ import com.android.systemui.util.kotlin.sample import com.android.wm.shell.animation.Interpolators import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine @@ -47,8 +49,10 @@ class FromPrimaryBouncerTransitionInteractor @Inject constructor( override val transitionRepository: KeyguardTransitionRepository, - override val transitionInteractor: KeyguardTransitionInteractor, - @Application private val scope: CoroutineScope, + transitionInteractor: KeyguardTransitionInteractor, + @Background private val scope: CoroutineScope, + @Background bgDispatcher: CoroutineDispatcher, + @Main mainDispatcher: CoroutineDispatcher, private val keyguardInteractor: KeyguardInteractor, private val flags: FeatureFlags, private val keyguardSecurityModel: KeyguardSecurityModel, @@ -57,6 +61,9 @@ constructor( ) : TransitionInteractor( fromState = KeyguardState.PRIMARY_BOUNCER, + transitionInteractor = transitionInteractor, + mainDispatcher = mainDispatcher, + bgDispatcher = bgDispatcher, ) { override fun start() { @@ -115,7 +122,7 @@ constructor( .distinctUntilChanged() fun dismissPrimaryBouncer() { - startTransitionTo(KeyguardState.GONE) + scope.launch { startTransitionTo(KeyguardState.GONE) } } private fun listenForPrimaryBouncerToLockscreenOrOccluded() { @@ -124,7 +131,7 @@ constructor( .sample( combine( powerInteractor.isAwake, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isKeyguardOccluded, keyguardInteractor.isActiveDreamLockscreenHosted, ::toQuad @@ -158,7 +165,7 @@ constructor( .sample( combine( powerInteractor.isAsleep, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, keyguardInteractor.isAodAvailable, ::Triple ), @@ -185,7 +192,7 @@ constructor( .sample( combine( keyguardInteractor.isActiveDreamLockscreenHosted, - transitionInteractor.startedKeyguardTransitionStep, + startedKeyguardTransitionStep, ::Pair ), ::toTriple @@ -213,7 +220,7 @@ constructor( scope.launch { keyguardInteractor.isKeyguardGoingAway - .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .sample(startedKeyguardTransitionStep, ::Pair) .collect { (isKeyguardGoingAway, lastStartedTransitionStep) -> if ( isKeyguardGoingAway && diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt new file mode 100644 index 000000000000..cb50839331a2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.domain.interactor + +import android.animation.ValueAnimator +import com.android.app.animation.Interpolators +import com.android.app.tracing.coroutines.launch +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalTransitionProgress +import com.android.systemui.communal.shared.model.CommunalSceneKey +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionInfo +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.util.kotlin.sample +import java.util.UUID +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope + +class GlanceableHubTransitions +@Inject +constructor( + @Application private val scope: CoroutineScope, + private val transitionInteractor: KeyguardTransitionInteractor, + private val transitionRepository: KeyguardTransitionRepository, + private val communalInteractor: CommunalInteractor, +) { + /** + * Listens for the glanceable hub transition to the specified scene and directly drives the + * keyguard transition between the lockscreen and the hub. + * + * The glanceable hub transition progress is used as the source of truth as it cannot be driven + * externally. The progress is used for both transitions caused by user touch input or by + * programmatic changes. + */ + fun listenForLockscreenAndHubTransition( + transitionName: String, + transitionOwnerName: String, + toScene: CommunalSceneKey + ) { + val fromState: KeyguardState + val toState: KeyguardState + if (toScene == CommunalSceneKey.Blank) { + fromState = KeyguardState.GLANCEABLE_HUB + toState = KeyguardState.LOCKSCREEN + } else { + fromState = KeyguardState.LOCKSCREEN + toState = KeyguardState.GLANCEABLE_HUB + } + var transitionId: UUID? = null + scope.launch("$transitionOwnerName#$transitionName") { + communalInteractor + .transitionProgressToScene(toScene) + .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair) + .collect { pair -> + val (transitionProgress, lastStartedStep) = pair + + val id = transitionId + if (id == null) { + // No transition started. + if ( + transitionProgress is CommunalTransitionProgress.Transition && + lastStartedStep.to == fromState + ) { + transitionId = + transitionRepository.startTransition( + TransitionInfo( + ownerName = transitionOwnerName, + from = fromState, + to = toState, + animator = null, // transition will be manually controlled + ) + ) + } + } else { + if (lastStartedStep.to != toState) { + return@collect + } + // An existing `id` means a transition is started, and calls to + // `updateTransition` will control it until FINISHED or CANCELED + val nextState: TransitionState + val progressFraction: Float + when (transitionProgress) { + is CommunalTransitionProgress.Idle -> { + if (transitionProgress.scene == toScene) { + nextState = TransitionState.FINISHED + progressFraction = 1f + } else { + nextState = TransitionState.CANCELED + progressFraction = 0f + } + } + is CommunalTransitionProgress.Transition -> { + nextState = TransitionState.RUNNING + progressFraction = transitionProgress.progress + } + is CommunalTransitionProgress.OtherTransition -> { + // Shouldn't happen but if another transition starts during the + // current one, mark the current one as canceled. + nextState = TransitionState.CANCELED + progressFraction = 0f + } + } + transitionRepository.updateTransition( + id, + progressFraction, + nextState, + ) + + if ( + nextState == TransitionState.CANCELED || + nextState == TransitionState.FINISHED + ) { + transitionId = null + } + + // If canceled, just put the state back. + if (nextState == TransitionState.CANCELED) { + transitionRepository.startTransition( + TransitionInfo( + ownerName = transitionOwnerName, + from = toState, + to = fromState, + animator = + ValueAnimator().apply { + interpolator = Interpolators.LINEAR + duration = 0 + } + ) + ) + } + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index f7d1543e4650..a8223ea83e1f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -27,6 +27,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING_LOCKSCREEN_HOSTED +import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED @@ -135,10 +136,18 @@ constructor( val lockscreenToDreamingLockscreenHostedTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, DREAMING_LOCKSCREEN_HOSTED) + /** LOCKSCREEN->GLANCEABLE_HUB transition information. */ + val lockscreenToGlanceableHubTransition: Flow<TransitionStep> = + repository.transition(LOCKSCREEN, GLANCEABLE_HUB) + /** LOCKSCREEN->OCCLUDED transition information. */ val lockscreenToOccludedTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, OCCLUDED) + /** GLANCEABLE_HUB->LOCKSCREEN transition information. */ + val glanceableHubToLockscreenTransition: Flow<TransitionStep> = + repository.transition(GLANCEABLE_HUB, LOCKSCREEN) + /** OCCLUDED->LOCKSCREEN transition information. */ val occludedToLockscreenTransition: Flow<TransitionStep> = repository.transition(OCCLUDED, LOCKSCREEN) @@ -154,6 +163,8 @@ constructor( val dozingToLockscreenTransition: Flow<TransitionStep> = repository.transition(DOZING, LOCKSCREEN) + val transitions = repository.transitions + /** Receive all [TransitionStep] matching a filter of [from]->[to] */ fun transition(from: KeyguardState, to: KeyguardState): Flow<TransitionStep> { return repository.transition(from, to) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index fbf693625f63..19d00cfea114 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -22,12 +22,15 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.power.shared.model.ScreenPowerState import com.android.systemui.statusbar.LightRevealEffect import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch @ExperimentalCoroutinesApi @@ -39,6 +42,7 @@ constructor( private val lightRevealScrimRepository: LightRevealScrimRepository, @Application private val scope: CoroutineScope, private val scrimLogger: ScrimLogger, + powerInteractor: PowerInteractor, ) { init { @@ -73,7 +77,16 @@ constructor( lightRevealScrimRepository.revealEffect ) - val revealAmount = lightRevealScrimRepository.revealAmount + val revealAmount = + lightRevealScrimRepository.revealAmount.filter { + // When the screen is off we do not want to keep producing frames as this is causing + // (invisible) jank. However, we need to still pass through 1f and 0f to ensure that the + // correct end states are respected even if the screen turned off (or was still off) + // when the animation finished + powerInteractor.screenPowerState.value != ScreenPowerState.SCREEN_OFF || + it == 1f || + it == 0f + } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt index d5ac2838a2f1..5c2df4581ff0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt @@ -24,8 +24,11 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.util.kotlin.sample import java.util.UUID +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext /** * Each TransitionInteractor is responsible for determining under which conditions to notify @@ -40,14 +43,25 @@ import kotlinx.coroutines.launch */ sealed class TransitionInteractor( val fromState: KeyguardState, + val transitionInteractor: KeyguardTransitionInteractor, + val mainDispatcher: CoroutineDispatcher, + val bgDispatcher: CoroutineDispatcher, ) { val name = this::class.simpleName ?: "UnknownTransitionInteractor" - abstract val transitionRepository: KeyguardTransitionRepository - abstract val transitionInteractor: KeyguardTransitionInteractor abstract fun start() - fun startTransitionTo( + /* Use background dispatcher for all [KeyguardTransitionInteractor] flows. Necessary because + * the [sample] utility internally runs a collect on the Unconfined dispatcher, resulting + * in continuations on the main thread. We don't want that for classes that inherit from this. + */ + val startedKeyguardTransitionStep = + transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher) + // The following are MutableSharedFlows, and do not require flowOn + val startedKeyguardState = transitionInteractor.startedKeyguardState + val finishedKeyguardState = transitionInteractor.finishedKeyguardState + + suspend fun startTransitionTo( toState: KeyguardState, animator: ValueAnimator? = getDefaultAnimatorForTransitionsToState(toState), modeOnCanceled: TransitionModeOnCanceled = TransitionModeOnCanceled.LAST_VALUE @@ -67,16 +81,17 @@ sealed class TransitionInteractor( ) return null } - - return transitionRepository.startTransition( - TransitionInfo( - name, - fromState, - toState, - animator, - modeOnCanceled, + return withContext(mainDispatcher) { + transitionRepository.startTransition( + TransitionInfo( + name, + fromState, + toState, + animator, + modeOnCanceled, + ) ) - ) + } } /** This signal may come in before the occlusion signal, and can provide a custom transition */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt index cf1d2477c9af..4abda741d495 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlow.kt @@ -17,9 +17,13 @@ package com.android.systemui.keyguard.ui import android.view.animation.Interpolator import com.android.app.animation.Interpolators.LINEAR +import com.android.app.tracing.coroutines.launch import com.android.keyguard.logging.KeyguardTransitionAnimationLogger import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState.CANCELED import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING @@ -31,10 +35,12 @@ import kotlin.math.min import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull /** * Assists in creating sub-flows for a KeyguardTransition. Call [setup] once for a transition, and @@ -45,21 +51,49 @@ class KeyguardTransitionAnimationFlow @Inject constructor( @Application private val scope: CoroutineScope, + private val transitionInteractor: KeyguardTransitionInteractor, private val logger: KeyguardTransitionAnimationLogger, ) { + private val transitionMap = mutableMapOf<Edge, MutableSharedFlow<TransitionStep>>() - /** - * Invoke once per transition between FROM->TO states to get access to - * [SharedFlowBuilder#sharedFlow]. - */ + init { + scope.launch("KeyguardTransitionAnimationFlow") { + transitionInteractor.transitions.collect { + // FROM->TO + transitionMap[Edge(it.from, it.to)]?.emit(it) + // FROM->(ANY) + transitionMap[Edge(it.from, null)]?.emit(it) + // (ANY)->TO + transitionMap[Edge(null, it.to)]?.emit(it) + } + } + } + + private fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> { + return transitionMap.getOrPut(edge) { + MutableSharedFlow<TransitionStep>( + extraBufferCapacity = 10, + onBufferOverflow = BufferOverflow.DROP_OLDEST + ) + } + } + + /** Invoke once per transition between FROM->TO states to get access to a shared flow. */ fun setup( duration: Duration, - stepFlow: Flow<TransitionStep>, - ) = SharedFlowBuilder(duration, stepFlow) + from: KeyguardState?, + to: KeyguardState?, + ): FlowBuilder { + if (from == null && to == null) { + throw IllegalArgumentException("from and to are both null") + } + + return FlowBuilder(duration, Edge(from, to)) + } - inner class SharedFlowBuilder( + inner class FlowBuilder( private val transitionDuration: Duration, - private val stepFlow: Flow<TransitionStep>, + private val edge: Edge, ) { /** * Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted @@ -115,20 +149,21 @@ constructor( }?.let { onStep(interpolator.getInterpolation(it)) } } - return stepFlow + return getOrCreateFlow(edge) .map { step -> - val value = - when (step.transitionState) { - STARTED -> stepToValue(step) - RUNNING -> stepToValue(step) - CANCELED -> onCancel?.invoke() - FINISHED -> onFinish?.invoke() - } - logger.logTransitionStep(name, step, value) - value + StateToValue( + step.transitionState, + when (step.transitionState) { + STARTED -> stepToValue(step) + RUNNING -> stepToValue(step) + CANCELED -> onCancel?.invoke() + FINISHED -> onFinish?.invoke() + } + ) + .also { logger.logTransitionStep(name, step, it.value) } } - .filterNotNull() .distinctUntilChanged() + .mapNotNull { stateToValue -> stateToValue.value } } /** @@ -138,4 +173,14 @@ constructor( return sharedFlow(duration = 1.milliseconds, onStep = { value }, onFinish = { value }) } } + + data class Edge( + val from: KeyguardState?, + val to: KeyguardState?, + ) + + data class StateToValue( + val transitionState: TransitionState, + val value: Float?, + ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt index 05fe0b25381d..bf763b4e1f99 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt @@ -16,13 +16,20 @@ package com.android.systemui.keyguard.ui.binder +import android.animation.Animator +import android.animation.ValueAnimator +import android.transition.Transition import android.transition.TransitionManager +import android.transition.TransitionSet +import android.transition.TransitionValues +import android.view.ViewGroup import androidx.annotation.VisibleForTesting import androidx.constraintlayout.helper.widget.Layer import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.app.animation.Interpolators import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection @@ -32,6 +39,8 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.res.R import kotlinx.coroutines.launch +private const val KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION_MS = 1000L + object KeyguardClockViewBinder { @JvmStatic fun bind( @@ -69,7 +78,13 @@ object KeyguardClockViewBinder { launch { if (!migrateClocksToBlueprint()) return@launch viewModel.clockShouldBeCentered.collect { - applyConstraints(clockSection, keyguardRootView, true) + viewModel.clock?.let { + if (it.largeClock.config.hasCustomPositionUpdatedAnimation) { + playClockCenteringAnimation(clockSection, keyguardRootView, it) + } else { + applyConstraints(clockSection, keyguardRootView, true) + } + } } } } @@ -125,12 +140,84 @@ object KeyguardClockViewBinder { clockSection: ClockSection, rootView: ConstraintLayout, animated: Boolean, + set: TransitionSet? = null, ) { val constraintSet = ConstraintSet().apply { clone(rootView) } clockSection.applyConstraints(constraintSet) if (animated) { - TransitionManager.beginDelayedTransition(rootView) + set?.let { TransitionManager.beginDelayedTransition(rootView, it) } + ?: run { TransitionManager.beginDelayedTransition(rootView) } } constraintSet.applyTo(rootView) } + + private fun playClockCenteringAnimation( + clockSection: ClockSection, + keyguardRootView: ConstraintLayout, + clock: ClockController, + ) { + // Find the clock, so we can exclude it from this transition. + val clockView = clock.largeClock.view + val set = TransitionSet() + val adapter = SplitShadeTransitionAdapter(clock) + adapter.setInterpolator(Interpolators.LINEAR) + adapter.setDuration(KEYGUARD_STATUS_VIEW_CUSTOM_CLOCK_MOVE_DURATION_MS) + adapter.addTarget(clockView) + set.addTransition(adapter) + applyConstraints(clockSection, keyguardRootView, true, set) + } + + internal class SplitShadeTransitionAdapter + @VisibleForTesting + constructor(private val clock: ClockController) : Transition() { + private fun captureValues(transitionValues: TransitionValues) { + transitionValues.values[PROP_BOUNDS_LEFT] = transitionValues.view.left + val locationInWindowTmp = IntArray(2) + transitionValues.view.getLocationInWindow(locationInWindowTmp) + transitionValues.values[PROP_X_IN_WINDOW] = locationInWindowTmp[0] + } + + override fun captureEndValues(transitionValues: TransitionValues) { + captureValues(transitionValues) + } + + override fun captureStartValues(transitionValues: TransitionValues) { + captureValues(transitionValues) + } + + override fun createAnimator( + sceneRoot: ViewGroup, + startValues: TransitionValues?, + endValues: TransitionValues? + ): Animator? { + if (startValues == null || endValues == null) { + return null + } + val anim = ValueAnimator.ofFloat(0f, 1f) + val fromLeft = startValues.values[PROP_BOUNDS_LEFT] as Int + val fromWindowX = startValues.values[PROP_X_IN_WINDOW] as Int + val toWindowX = endValues.values[PROP_X_IN_WINDOW] as Int + // Using windowX, to determine direction, instead of left, as in RTL the difference of + // toLeft - fromLeft is always positive, even when moving left. + val direction = if (toWindowX - fromWindowX > 0) 1 else -1 + anim.addUpdateListener { animation: ValueAnimator -> + clock.largeClock.animations.onPositionUpdated( + fromLeft, + direction, + animation.animatedFraction + ) + } + return anim + } + + override fun getTransitionProperties(): Array<String> { + return TRANSITION_PROPERTIES + } + + companion object { + private const val PROP_BOUNDS_LEFT = "splitShadeTransitionAdapter:boundsLeft" + private const val PROP_X_IN_WINDOW = "splitShadeTransitionAdapter:xInWindow" + private val TRANSITION_PROPERTIES = arrayOf(PROP_BOUNDS_LEFT, PROP_X_IN_WINDOW) + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt index 92270ad31664..81ce8f04d302 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt @@ -23,6 +23,7 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle +import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel @@ -42,6 +43,7 @@ object KeyguardSmartspaceViewBinder { keyguardRootView.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.STARTED) { launch { + if (!migrateClocksToBlueprint()) return@launch clockViewModel.hasCustomWeatherDataDisplay.collect { hasCustomWeatherDataDisplay -> if (hasCustomWeatherDataDisplay) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt index 920fc04168a7..fab60e8a558c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.transitions import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel @@ -53,6 +54,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun alternateBouncerToPrimaryBouncer( + impl: AlternateBouncerToPrimaryBouncerTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun aodToLockscreen( impl: AodToLockscreenTransitionViewModel ): DeviceEntryIconTransition diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt index f2b28d964314..f33aed03856c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/KeyguardRootView.kt @@ -29,4 +29,8 @@ class KeyguardRootView( ConstraintLayout( context, attrs, - ) + ) { + init { + clipChildren = false + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt index 9b404338b9e5..d118d4d11948 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt @@ -17,12 +17,14 @@ package com.android.systemui.keyguard.ui.view.layout.blueprints +import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection +import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection @@ -31,7 +33,7 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSec import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection import com.android.systemui.keyguard.ui.view.layout.sections.DefaultUdfpsAccessibilityOverlaySection import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule -import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines +import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection import com.android.systemui.util.kotlin.getOrNull import java.util.Optional import javax.inject.Inject @@ -44,18 +46,20 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi class ShortcutsBesideUdfpsKeyguardBlueprint @Inject constructor( + alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection, defaultIndicationAreaSection: DefaultIndicationAreaSection, defaultDeviceEntrySection: DefaultDeviceEntrySection, @Named(KeyguardSectionsModule.KEYGUARD_AMBIENT_INDICATION_AREA_SECTION) defaultAmbientIndicationAreaSection: Optional<KeyguardSection>, defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection, - alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection, defaultStatusViewSection: DefaultStatusViewSection, defaultStatusBarSection: DefaultStatusBarSection, - splitShadeGuidelines: SplitShadeGuidelines, defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection, aodNotificationIconsSection: AodNotificationIconsSection, aodBurnInSection: AodBurnInSection, + communalTutorialIndicatorSection: CommunalTutorialIndicatorSection, + clockSection: ClockSection, + smartspaceSection: SmartspaceSection, udfpsAccessibilityOverlaySection: DefaultUdfpsAccessibilityOverlaySection, ) : KeyguardBlueprint { override val id: String = SHORTCUTS_BESIDE_UDFPS @@ -63,15 +67,17 @@ constructor( override val sections = listOfNotNull( defaultIndicationAreaSection, + alignShortcutsToUdfpsSection, defaultAmbientIndicationAreaSection.getOrNull(), defaultSettingsPopupMenuSection, - alignShortcutsToUdfpsSection, defaultStatusViewSection, defaultStatusBarSection, defaultNotificationStackScrollLayoutSection, - splitShadeGuidelines, aodNotificationIconsSection, + smartspaceSection, aodBurnInSection, + communalTutorialIndicatorSection, + clockSection, defaultDeviceEntrySection, udfpsAccessibilityOverlaySection, // Add LAST: Intentionally has z-order above others ) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt index 0f8e67340cc7..756a4cca69d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt @@ -23,11 +23,13 @@ import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP +import com.android.systemui.Flags.centralizedStatusBarDimensRefactor import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlags +import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.NotificationPanelView import com.android.systemui.statusbar.notification.stack.AmbientState import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController @@ -35,6 +37,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCa import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel +import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -53,6 +56,7 @@ constructor( notificationStackSizeCalculator: NotificationStackSizeCalculator, private val smartspaceViewModel: KeyguardSmartspaceViewModel, @Main mainDispatcher: CoroutineDispatcher, + private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, ) : NotificationStackScrollLayoutSection( context, @@ -72,7 +76,13 @@ constructor( } constraintSet.apply { val splitShadeTopMargin = - context.resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height) + if (centralizedStatusBarDimensRefactor()) { + largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + } else { + context.resources.getDimensionPixelSize( + R.dimen.large_screen_shade_header_height + ) + } connect(R.id.nssl_placeholder, TOP, PARENT_ID, TOP, splitShadeTopMargin) connect(R.id.nssl_placeholder, START, PARENT_ID, START) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt index a8e3be79fc5a..b4b48a8fb932 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -38,14 +37,14 @@ import kotlinx.coroutines.flow.flatMapLatest class AlternateBouncerToAodTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromAlternateBouncerTransitionInteractor.TO_AOD_DURATION, - stepFlow = interactor.transition(KeyguardState.ALTERNATE_BOUNCER, KeyguardState.AOD), + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.AOD, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt index 5d6b0cebf959..3737e6fdf13e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TO_GONE_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.shared.model.ScrimAlpha @@ -37,14 +36,14 @@ import kotlinx.coroutines.flow.Flow class AlternateBouncerToGoneTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, bouncerToGoneFlows: BouncerToGoneFlows, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = TO_GONE_DURATION, - stepFlow = interactor.transition(ALTERNATE_BOUNCER, KeyguardState.GONE), + from = ALTERNATE_BOUNCER, + to = KeyguardState.GONE, ) /** Scrim alpha values */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt new file mode 100644 index 000000000000..759288136783 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModel.kt @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down ALTERNATE BOUNCER->PRIMARY BOUNCER transition into discrete steps for corresponding + * views to consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class AlternateBouncerToPrimaryBouncerTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + private val transitionAnimation = + animationFlow.setup( + duration = FromAlternateBouncerTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.PRIMARY_BOUNCER, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt index fa4de044623d..ce4511237e40 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt @@ -17,14 +17,12 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context -import android.hardware.biometrics.SensorLocationInternal import com.android.settingslib.Utils -import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository +import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.view.DeviceEntryIconView -import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow @@ -44,21 +42,24 @@ constructor( configurationInteractor: ConfigurationInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, deviceEntryBackgroundViewModel: DeviceEntryBackgroundViewModel, - fingerprintPropertyRepository: FingerprintPropertyRepository, + fingerprintPropertyInteractor: FingerprintPropertyInteractor, udfpsOverlayInteractor: UdfpsOverlayInteractor, ) { private val isSupported: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported + + /** + * UDFPS icon location in pixels for the current display and screen resolution, in natural + * orientation. + */ val iconLocation: Flow<IconLocation> = isSupported.flatMapLatest { supportsUI -> if (supportsUI) { - fingerprintPropertyRepository.sensorLocations.map { sensorLocations -> - val sensorLocation = - sensorLocations.getOrDefault("", SensorLocationInternal.DEFAULT) + fingerprintPropertyInteractor.sensorLocation.map { sensorLocation -> IconLocation( - left = sensorLocation.sensorLocationX - sensorLocation.sensorRadius, - top = sensorLocation.sensorLocationY - sensorLocation.sensorRadius, - right = sensorLocation.sensorLocationX + sensorLocation.sensorRadius, - bottom = sensorLocation.sensorLocationY + sensorLocation.sensorRadius, + left = (sensorLocation.centerX - sensorLocation.radius).toInt(), + top = (sensorLocation.centerY - sensorLocation.radius).toInt(), + right = (sensorLocation.centerX + sensorLocation.radius).toInt(), + bottom = (sensorLocation.centerY + sensorLocation.radius).toInt(), ) } } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt index 8e729f76e096..2526f0aec796 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import android.graphics.Color import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor.Companion.TRANSITION_DURATION_MS -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager @@ -37,7 +36,6 @@ class AlternateBouncerViewModel @Inject constructor( private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager, - transitionInteractor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { // When we're fully transitioned to the AlternateBouncer, the alpha of the scrim should be: @@ -46,7 +44,8 @@ constructor( animationFlow .setup( duration = TRANSITION_DURATION_MS, - stepFlow = transitionInteractor.anyStateToAlternateBouncerTransition, + from = null, + to = ALTERNATE_BOUNCER, ) .sharedFlow( duration = TRANSITION_DURATION_MS, @@ -60,7 +59,8 @@ constructor( animationFlow .setup( TRANSITION_DURATION_MS, - transitionInteractor.transitionStepsFromState(ALTERNATE_BOUNCER), + from = ALTERNATE_BOUNCER, + to = null, ) .sharedFlow( duration = TRANSITION_DURATION_MS, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt index 2b145216cb80..b92a9a08987a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -31,14 +30,14 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi class AodToGoneTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromAodTransitionInteractor.TO_GONE_DURATION, - stepFlow = interactor.transition(KeyguardState.AOD, KeyguardState.GONE), + from = KeyguardState.AOD, + to = KeyguardState.GONE, ) override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt index 5e552e1fe00f..266fd02d5bbf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt @@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject @@ -37,7 +37,6 @@ import kotlinx.coroutines.flow.flatMapLatest class AodToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { @@ -45,7 +44,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_LOCKSCREEN_DURATION, - stepFlow = interactor.aodToLockscreenTransition, + from = KeyguardState.AOD, + to = KeyguardState.LOCKSCREEN, ) /** Ensure alpha is set to be visible */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt index d283af359b06..105a7ed52311 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -29,13 +28,13 @@ import javax.inject.Inject class AodToOccludedTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromAodTransitionInteractor.TO_OCCLUDED_DURATION, - stepFlow = interactor.transition(KeyguardState.AOD, KeyguardState.OCCLUDED), + from = KeyguardState.AOD, + to = KeyguardState.OCCLUDED, ) override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt index 41dc15778b0c..924fc5d0333f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlows.kt @@ -21,7 +21,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.ScrimAlpha @@ -41,7 +40,6 @@ import kotlinx.coroutines.flow.map class BouncerToGoneFlows @Inject constructor( - private val interactor: KeyguardTransitionInteractor, private val statusBarStateController: SysuiStatusBarStateController, private val primaryBouncerInteractor: PrimaryBouncerInteractor, private val keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, @@ -76,7 +74,8 @@ constructor( val transitionAnimation = animationFlow.setup( duration = duration, - stepFlow = interactor.transition(fromState, GONE) + from = fromState, + to = GONE, ) return shadeInteractor.shadeExpansion.flatMapLatest { shadeExpansion -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt index fe0b3656c3d7..310ec95a22df 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt @@ -20,7 +20,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context import com.android.settingslib.Utils import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor -import com.android.systemui.common.ui.data.repository.ConfigurationRepository +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState @@ -41,7 +41,7 @@ class DeviceEntryForegroundViewModel @Inject constructor( val context: Context, - configurationRepository: ConfigurationRepository, // TODO (b/309655554): create & use interactor + configurationInteractor: ConfigurationInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, transitionInteractor: KeyguardTransitionInteractor, deviceEntryIconViewModel: DeviceEntryIconViewModel, @@ -62,7 +62,7 @@ constructor( private val color: Flow<Int> = deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBgProtection -> - configurationRepository.onAnyConfigurationChange + configurationInteractor.onAnyConfigurationChange .map { getColor(useBgProtection) } .onStart { emit(getColor(useBgProtection)) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt index 0b34326bc83d..e4610c15a3d0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject @@ -34,13 +34,13 @@ import kotlinx.coroutines.flow.Flow class DozingToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromDozingTransitionInteractor.TO_LOCKSCREEN_DURATION, - stepFlow = interactor.dozingToLockscreenTransition, + from = KeyguardState.DOZING, + to = KeyguardState.LOCKSCREEN, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt index 8bcf3f8a76d9..67568e12a4a1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingHostedToLockscreenTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromDreamingLockscreenHostedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -28,14 +28,14 @@ import kotlinx.coroutines.flow.Flow class DreamingHostedToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_LOCKSCREEN_DURATION, - stepFlow = interactor.dreamingLockscreenHostedToLockscreenTransition, + from = KeyguardState.DREAMING_LOCKSCREEN_HOSTED, + to = KeyguardState.LOCKSCREEN, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt index 5f620afe2dea..ead2d48240c0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt @@ -22,6 +22,7 @@ import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsIntera import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -52,7 +53,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_LOCKSCREEN_DURATION, - stepFlow = keyguardTransitionInteractor.dreamingToLockscreenTransition, + from = KeyguardState.DREAMING, + to = KeyguardState.LOCKSCREEN, ) val transitionEnded = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt new file mode 100644 index 000000000000..bc518210a067 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModel.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down GLANCEABLE_HUB->LOCKSCREEN transition into discrete steps for corresponding views to + * consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class GlanceableHubToLockscreenTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) { + private val transitionAnimation = + animationFlow.setup( + duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION, + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.LOCKSCREEN, + ) + + // TODO(b/315205222): implement full animation spec instead of just a simple fade. + val keyguardAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION, + onStep = { it }, + onFinish = { 1f }, + onCancel = { 0f }, + name = "GLANCEABLE_HUB->LOCKSCREEN: keyguardAlpha", + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt index 3f27eb0c73e3..ba04fd3741a4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModel.kt @@ -20,7 +20,7 @@ import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_AOD_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject @@ -36,7 +36,6 @@ import kotlinx.coroutines.flow.flatMapLatest class GoneToAodTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { @@ -44,7 +43,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_AOD_DURATION, - stepFlow = interactor.goneToAodTransition, + from = KeyguardState.GONE, + to = KeyguardState.AOD, ) /** y-translation from the top of the screen for AOD */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt index bba790abe807..b52746364a8b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingLockscreenHostedTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -32,14 +32,14 @@ import kotlinx.coroutines.flow.Flow class GoneToDreamingLockscreenHostedTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_DREAMING_DURATION, - stepFlow = interactor.goneToDreamingLockscreenHostedTransition, + from = KeyguardState.GONE, + to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED, ) /** Lockscreen views alpha - hide immediately */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt index 6762ba6298a5..102242a4a7b0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModel.kt @@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DREAMING_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -30,14 +30,14 @@ import kotlinx.coroutines.flow.Flow class GoneToDreamingTransitionViewModel @Inject constructor( - private val interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_DREAMING_DURATION, - stepFlow = interactor.goneToDreamingTransition, + from = KeyguardState.GONE, + to = KeyguardState.DREAMING, ) /** Lockscreen views y-translation */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt index adae8abfb9c3..793abb444f31 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToLockscreenTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -28,14 +28,14 @@ import kotlinx.coroutines.flow.Flow class GoneToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_LOCKSCREEN_DURATION, - stepFlow = interactor.goneToLockscreenTransition + from = KeyguardState.GONE, + to = KeyguardState.LOCKSCREEN ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 5059e6be9080..5d36da9b9df1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -46,6 +46,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton @@ -58,6 +59,8 @@ constructor( keyguardTransitionInteractor: KeyguardTransitionInteractor, private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor, aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel, + lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel, + glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, screenOffAnimationController: ScreenOffAnimationController, private val aodBurnInViewModel: AodBurnInViewModel, aodAlphaViewModel: AodAlphaViewModel, @@ -78,7 +81,13 @@ constructor( keyguardInteractor.notificationContainerBounds /** An observable for the alpha level for the entire keyguard root view. */ - val alpha: Flow<Float> = aodAlphaViewModel.alpha + val alpha: Flow<Float> = + merge( + aodAlphaViewModel.alpha, + lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha, + glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, + ) + .distinctUntilChanged() /** Specific alpha value for elements visible during [KeyguardState.LOCKSCREEN] */ val lockscreenStateAlpha: Flow<Float> = aodToLockscreenTransitionViewModel.lockscreenAlpha diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt index 65614f47b120..7bf51a7d3d54 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt @@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject @@ -36,7 +36,6 @@ import kotlinx.coroutines.flow.flatMapLatest class LockscreenToAodTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, shadeDependentFlows: ShadeDependentFlows, animationFlow: KeyguardTransitionAnimationFlow, @@ -45,7 +44,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = FromLockscreenTransitionInteractor.TO_AOD_DURATION, - stepFlow = interactor.lockscreenToAodTransition, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt index accb20c91f98..4c0cd2f58eb7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DOZING_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -28,14 +28,14 @@ import kotlinx.coroutines.flow.Flow class LockscreenToDozingTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_DOZING_DURATION, - stepFlow = interactor.lockscreenToDozingTransition + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DOZING, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt index c649b12b71e4..19b9cf4733f9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingHostedTransitionViewModel.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_HOSTED_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -28,14 +28,14 @@ import kotlinx.coroutines.flow.Flow class LockscreenToDreamingHostedTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = TO_DREAMING_HOSTED_DURATION, - stepFlow = interactor.lockscreenToDreamingLockscreenHostedTransition + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DREAMING_LOCKSCREEN_HOSTED, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt index 7f75b547d717..13522a6742ac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModel.kt @@ -19,7 +19,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DREAMING_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject @@ -34,14 +34,14 @@ import kotlinx.coroutines.flow.Flow class LockscreenToDreamingTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = TO_DREAMING_DURATION, - stepFlow = interactor.lockscreenToDreamingTransition, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DREAMING, ) /** Lockscreen views y-translation */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt new file mode 100644 index 000000000000..3ea83ae21085 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModel.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down LOCKSCREEN->GLANCEABLE_HUB transition into discrete steps for corresponding views to + * consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class LockscreenToGlanceableHubTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) { + private val transitionAnimation = + animationFlow.setup( + duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GLANCEABLE_HUB, + ) + + // TODO(b/315205222): implement full animation spec instead of just a simple fade. + val keyguardAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = FromLockscreenTransitionInteractor.TO_GLANCEABLE_HUB_DURATION, + onStep = { 1f - it }, + onFinish = { 0f }, + onCancel = { 1f }, + name = "LOCKSCREEN->GLANCEABLE_HUB: keyguardAlpha", + ) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt index 9e197138d0b2..a26ef0755123 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -35,14 +34,14 @@ import kotlinx.coroutines.flow.Flow class LockscreenToGoneTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromLockscreenTransitionInteractor.TO_GONE_DURATION, - stepFlow = interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.GONE), + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.GONE, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt index 9db0b775cd40..dd6652e69792 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModel.kt @@ -20,7 +20,7 @@ import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_OCCLUDED_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.res.R @@ -37,7 +37,6 @@ import kotlinx.coroutines.flow.flatMapLatest class LockscreenToOccludedTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, configurationInteractor: ConfigurationInteractor, animationFlow: KeyguardTransitionAnimationFlow, @@ -46,7 +45,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_OCCLUDED_DURATION, - stepFlow = interactor.lockscreenToOccludedTransition, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.OCCLUDED, ) /** Lockscreen views alpha */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt index 52e3257f8e18..ce47f3c67b21 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -26,7 +25,6 @@ import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map /** * Breaks down LOCKSCREEN->PRIMARY BOUNCER transition into discrete steps for corresponding views to @@ -37,21 +35,21 @@ import kotlinx.coroutines.flow.map class LockscreenToPrimaryBouncerTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, shadeDependentFlows: ShadeDependentFlows, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, - stepFlow = - interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER), + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.PRIMARY_BOUNCER, ) val shortcutsAlpha: Flow<Float> = - interactor.transition(KeyguardState.LOCKSCREEN, KeyguardState.PRIMARY_BOUNCER).map { - 1 - it.value - } + transitionAnimation.sharedFlow( + duration = FromLockscreenTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION, + onStep = { 1f - it } + ) override val deviceEntryParentViewAlpha: Flow<Float> = shadeDependentFlows.transitionFlow( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt index ed5e83c44640..07c114163326 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -35,14 +34,14 @@ import kotlinx.coroutines.flow.flatMapLatest class OccludedToAodTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromOccludedTransitionInteractor.TO_AOD_DURATION, - stepFlow = interactor.transition(KeyguardState.OCCLUDED, KeyguardState.AOD), + from = KeyguardState.OCCLUDED, + to = KeyguardState.AOD, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt index 4c24f83200b2..90195bd343b7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt @@ -21,7 +21,7 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.res.R @@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.flatMapLatest class OccludedToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, configurationInteractor: ConfigurationInteractor, animationFlow: KeyguardTransitionAnimationFlow, @@ -50,7 +49,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_LOCKSCREEN_DURATION, - stepFlow = interactor.occludedToLockscreenTransition, + from = KeyguardState.OCCLUDED, + to = KeyguardState.LOCKSCREEN, ) /** Lockscreen views y-translation */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt index 93482ea162bb..74094bea140a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OffToLockscreenTransitionViewModel.kt @@ -17,7 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -27,14 +27,14 @@ import kotlinx.coroutines.flow.Flow class OffToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) { private val transitionAnimation = animationFlow.setup( duration = 250.milliseconds, - stepFlow = interactor.offToLockscreenTransition + from = KeyguardState.OFF, + to = KeyguardState.LOCKSCREEN, ) val shortcutsAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt index b0e2aa2d4765..cd8e2f12cb19 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -39,14 +38,14 @@ import kotlinx.coroutines.flow.flatMapLatest class PrimaryBouncerToAodTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromPrimaryBouncerTransitionInteractor.TO_AOD_DURATION, - stepFlow = interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.AOD), + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.AOD, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index 9dbe97fd1c20..4f28b4608e49 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -22,7 +22,6 @@ import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_GONE_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardDismissActionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState.GONE import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.keyguard.shared.model.ScrimAlpha @@ -44,7 +43,6 @@ import kotlinx.coroutines.flow.flatMapLatest class PrimaryBouncerToGoneTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, private val statusBarStateController: SysuiStatusBarStateController, private val primaryBouncerInteractor: PrimaryBouncerInteractor, keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>, @@ -55,7 +53,8 @@ constructor( private val transitionAnimation = animationFlow.setup( duration = TO_GONE_DURATION, - stepFlow = interactor.transition(PRIMARY_BOUNCER, GONE) + from = PRIMARY_BOUNCER, + to = GONE, ) private var leaveShadeOpen: Boolean = false diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt index b2eed60e0a9e..284a134f73c7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModel.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition @@ -28,7 +27,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map /** * Breaks down PRIMARY BOUNCER->LOCKSCREEN transition into discrete steps for corresponding views to @@ -39,15 +37,14 @@ import kotlinx.coroutines.flow.map class PrimaryBouncerToLockscreenTransitionViewModel @Inject constructor( - interactor: KeyguardTransitionInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION, - stepFlow = - interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.LOCKSCREEN), + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.LOCKSCREEN, ) val deviceEntryBackgroundViewAlpha: Flow<Float> = @@ -60,9 +57,10 @@ constructor( } val shortcutsAlpha: Flow<Float> = - interactor.transition(KeyguardState.PRIMARY_BOUNCER, KeyguardState.LOCKSCREEN).map { - it.value - } + transitionAnimation.sharedFlow( + duration = FromPrimaryBouncerTransitionInteractor.TO_LOCKSCREEN_DURATION, + onStep = { it } + ) override val deviceEntryParentViewAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(1f) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 2551da8e7795..5720cc74002b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -87,8 +87,6 @@ import com.android.systemui.bluetooth.BroadcastDialogController; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.flags.Flags; import com.android.systemui.media.controls.models.GutsViewHolder; import com.android.systemui.media.controls.models.player.MediaAction; import com.android.systemui.media.controls.models.player.MediaButton; @@ -247,7 +245,6 @@ public class MediaControlPanel { private String mCurrentBroadcastApp; private MultiRippleController mMultiRippleController; private TurbulenceNoiseController mTurbulenceNoiseController; - private final FeatureFlags mFeatureFlags; private final GlobalSettings mGlobalSettings; private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig; @@ -281,7 +278,6 @@ public class MediaControlPanel { ActivityIntentHelper activityIntentHelper, NotificationLockscreenUserManager lockscreenUserManager, BroadcastDialogController broadcastDialogController, - FeatureFlags featureFlags, GlobalSettings globalSettings, MediaFlags mediaFlags ) { @@ -312,8 +308,6 @@ public class MediaControlPanel { return Unit.INSTANCE; }); - mFeatureFlags = featureFlags; - mGlobalSettings = globalSettings; updateAnimatorDurationScale(); } @@ -1187,9 +1181,7 @@ public class MediaControlPanel { action.run(); - if (mFeatureFlags.isEnabled(Flags.UMO_SURFACE_RIPPLE)) { - mMultiRippleController.play(createTouchRippleAnimation(button)); - } + mMultiRippleController.play(createTouchRippleAnimation(button)); if (icon instanceof Animatable) { ((Animatable) icon).start(); @@ -1228,8 +1220,7 @@ public class MediaControlPanel { } private boolean shouldPlayTurbulenceNoise() { - return mFeatureFlags.isEnabled(Flags.UMO_TURBULENCE_NOISE) && mButtonClicked && !mWasPlaying - && isPlaying(); + return mButtonClicked && !mWasPlaying && isPlaying(); } private TurbulenceNoiseAnimationConfig createTurbulenceNoiseAnimation() { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt index 0385aeba32b7..523414cfddbf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt @@ -1153,7 +1153,7 @@ constructor( qsExpansion > 0.4f && onLockscreen -> LOCATION_QS onLockscreen && isSplitShadeExpanding() -> LOCATION_QS onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS - // TODO(b/308813166): revisit logic once interactions between the hub and + // TODO(b/311234666): revisit logic once interactions between the hub and // shade/keyguard state are finalized isCommunalShowing && communalInteractor.isCommunalEnabled -> LOCATION_COMMUNAL_HUB onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java index 0320dec0580f..092f1ed7d498 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java @@ -302,9 +302,6 @@ public class NavigationBarControllerImpl implements final NavigationBarView navBarView = getNavigationBarView(displayId); if (navBarView != null) { navBarView.showPinningEnterExitToast(entering); - } else if (displayId == mDisplayTracker.getDefaultDisplayId() - && mTaskbarDelegate.isInitialized()) { - mTaskbarDelegate.showPinningEnterExitToast(entering); } } @@ -314,9 +311,6 @@ public class NavigationBarControllerImpl implements final NavigationBarView navBarView = getNavigationBarView(displayId); if (navBarView != null) { navBarView.showPinningEscapeToast(); - } else if (displayId == mDisplayTracker.getDefaultDisplayId() - && mTaskbarDelegate.isInitialized()) { - mTaskbarDelegate.showPinningEscapeToast(); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index 62c7343d3fe5..01672875fd44 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -504,6 +504,11 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, } @Override + public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + mOverviewProxyService.onNavigationBarLumaSamplingEnabled(displayId, enable); + } + + @Override public void showPinningEnterExitToast(boolean entering) { updateSysuiFlags(); if (mScreenPinningNotify == null) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java index 064423768cd3..a3b92541d593 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java @@ -18,6 +18,8 @@ package com.android.systemui.qs; import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; +import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor; + import android.content.Context; import android.graphics.Canvas; import android.graphics.Path; @@ -30,6 +32,7 @@ import android.widget.FrameLayout; import com.android.systemui.Dumpable; import com.android.systemui.qs.customize.QSCustomizer; import com.android.systemui.res.R; +import com.android.systemui.shade.LargeScreenHeaderHelper; import com.android.systemui.shade.TouchLogger; import com.android.systemui.util.LargeScreenUtils; @@ -162,8 +165,12 @@ public class QSContainerImpl extends FrameLayout implements Dumpable { QuickStatusBarHeaderController quickStatusBarHeaderController) { int topPadding = QSUtils.getQsHeaderSystemIconsAreaHeight(mContext); if (!LargeScreenUtils.shouldUseLargeScreenShadeHeader(mContext.getResources())) { - topPadding = mContext.getResources() - .getDimensionPixelSize(R.dimen.large_screen_shade_header_height); + topPadding = + centralizedStatusBarDimensRefactor() + ? LargeScreenHeaderHelper.getLargeScreenHeaderHeight(mContext) + : mContext.getResources() + .getDimensionPixelSize( + R.dimen.large_screen_shade_header_height); } mQSPanelContainer.setPaddingRelative( mQSPanelContainer.getPaddingStart(), diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt index fc06090750ec..fe10eaaec793 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt @@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles.base.actions import android.app.PendingIntent import android.content.Intent +import android.content.pm.PackageManager +import android.os.UserHandle import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator @@ -32,13 +34,23 @@ import javax.inject.Inject interface QSTileIntentUserInputHandler { fun handle(view: View?, intent: Intent) - fun handle(view: View?, pendingIntent: PendingIntent) + + /** @param requestLaunchingDefaultActivity used in case !pendingIndent.isActivity */ + fun handle( + view: View?, + pendingIntent: PendingIntent, + requestLaunchingDefaultActivity: Boolean = false + ) } @SysUISingleton class QSTileIntentUserInputHandlerImpl @Inject -constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler { +constructor( + private val activityStarter: ActivityStarter, + private val packageManager: PackageManager, + private val userHandle: UserHandle, +) : QSTileIntentUserInputHandler { override fun handle(view: View?, intent: Intent) { val animationController: ActivityLaunchAnimator.Controller? = @@ -52,21 +64,41 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu } // TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939 - override fun handle(view: View?, pendingIntent: PendingIntent) { - if (!pendingIntent.isActivity) { - return - } - val animationController: ActivityLaunchAnimator.Controller? = - view?.let { - ActivityLaunchAnimator.Controller.fromView( - it, - InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, + override fun handle( + view: View?, + pendingIntent: PendingIntent, + requestLaunchingDefaultActivity: Boolean + ) { + if (pendingIntent.isActivity) { + val animationController: ActivityLaunchAnimator.Controller? = + view?.let { + ActivityLaunchAnimator.Controller.fromView( + it, + InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE, + ) + } + activityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController) + } else if (requestLaunchingDefaultActivity) { + val intent = + Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setPackage(pendingIntent.creatorPackage) + .addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED + ) + val intents = + packageManager.queryIntentActivitiesAsUser( + intent, + PackageManager.ResolveInfoFlags.of(0L), + userHandle.identifier ) - } - activityStarter.startPendingIntentMaybeDismissingKeyguard( - pendingIntent, - null, - animationController - ) + intents + .firstOrNull { it.activityInfo.exported } + ?.let { resolved -> + intent.setPackage(null) + intent.setComponent(resolved.activityInfo.componentName) + handle(view, intent) + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt index afca57c75788..0ad520bd31ee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt @@ -18,9 +18,7 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor import android.content.Intent import android.provider.AlarmClock -import com.android.internal.jank.InteractionJankMonitor -import com.android.systemui.animation.ActivityLaunchAnimator -import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel @@ -31,34 +29,20 @@ import javax.inject.Inject class AlarmTileUserActionInteractor @Inject constructor( - private val activityStarter: ActivityStarter, + private val inputHandler: QSTileIntentUserInputHandler, ) : QSTileUserActionInteractor<AlarmTileModel> { override suspend fun handleInput(input: QSTileInput<AlarmTileModel>): Unit = with(input) { when (action) { is QSTileUserAction.Click -> { - val animationController = - action.view?.let { - ActivityLaunchAnimator.Controller.fromView( - it, - InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE - ) - } if ( data is AlarmTileModel.NextAlarmSet && data.alarmClockInfo.showIntent != null ) { val pendingIndent = data.alarmClockInfo.showIntent - activityStarter.postStartActivityDismissingKeyguard( - pendingIndent, - animationController - ) + inputHandler.handle(action.view, pendingIndent, true) } else { - activityStarter.postStartActivityDismissingKeyguard( - Intent(AlarmClock.ACTION_SHOW_ALARMS), - 0, - animationController - ) + inputHandler.handle(action.view, Intent(AlarmClock.ACTION_SHOW_ALARMS)) } } is QSTileUserAction.LongClick -> {} diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 45917e85d80e..fd53423e7f22 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -1037,6 +1037,19 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) { + try { + if (mOverviewProxy != null) { + mOverviewProxy.onNavigationBarLumaSamplingEnabled(displayId, enable); + } else { + Log.e(TAG_OPS, "Failed to get overview proxy to enable/disable nav bar luma" + + "sampling"); + } + } catch (RemoteException e) { + Log.e(TAG_OPS, "Failed to call onNavigationBarLumaSamplingEnabled()", e); + } + } + private void updateEnabledState() { final int currentUser = mUserTracker.getUserId(); mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent, diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index bd43307dba5a..7aa0dadba16c 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -32,6 +32,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -143,6 +144,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList channel.enableVibration(true); mNotificationManager.createNotificationChannel(channel); + int currentUid = Process.myUid(); int currentUserId = mUserContextTracker.getUserContext().getUserId(); UserHandle currentUser = new UserHandle(currentUserId); switch (action) { @@ -166,7 +168,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList mRecorder = new ScreenMediaRecorder( mUserContextTracker.getUserContext(), mMainHandler, - currentUserId, + currentUid, mAudioSource, captureTarget, this diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java index 3aab3bf62809..a170d0dac100 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java @@ -83,7 +83,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { private Surface mInputSurface; private VirtualDisplay mVirtualDisplay; private MediaRecorder mMediaRecorder; - private int mUser; + private int mUid; private ScreenRecordingMuxer mMuxer; private ScreenInternalAudioRecorder mAudio; private ScreenRecordingAudioSource mAudioSource; @@ -94,12 +94,12 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { ScreenMediaRecorderListener mListener; public ScreenMediaRecorder(Context context, Handler handler, - int user, ScreenRecordingAudioSource audioSource, + int uid, ScreenRecordingAudioSource audioSource, MediaProjectionCaptureTarget captureRegion, ScreenMediaRecorderListener listener) { mContext = context; mHandler = handler; - mUser = user; + mUid = uid; mCaptureRegion = captureRegion; mListener = listener; mAudioSource = audioSource; @@ -111,7 +111,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback { IMediaProjectionManager mediaService = IMediaProjectionManager.Stub.asInterface(b); IMediaProjection proj = null; - proj = mediaService.createProjection(mUser, mContext.getPackageName(), + proj = mediaService.createProjection(mUid, mContext.getPackageName(), MediaProjectionManager.TYPE_SCREEN_CAPTURE, false); IMediaProjection projection = IMediaProjection.Stub.asInterface(proj.asBinder()); if (mCaptureRegion != null) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 3be60b74af21..782d6519468c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -17,6 +17,8 @@ package com.android.systemui.shade import android.content.Context +import android.os.PowerManager +import android.os.SystemClock import android.view.GestureDetector import android.view.MotionEvent import android.view.View @@ -44,6 +46,7 @@ constructor( private val communalViewModel: CommunalViewModel, private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val shadeInteractor: ShadeInteractor, + private val powerManager: PowerManager, ) { /** The container view for the hub. This will not be initialized until [initView] is called. */ private lateinit var communalContainerView: View @@ -157,7 +160,7 @@ constructor( // If the hub is fully visible, send all touch events to it. val communalVisible = hubShowing && !hubOccluded if (communalVisible) { - communalContainerView.dispatchTouchEvent(ev) + dispatchTouchEvent(ev) // Return true regardless of dispatch result as some touches at the start of a gesture // may return false from dispatchTouchEvent. return true @@ -175,7 +178,7 @@ constructor( x >= communalContainerView.width - edgeSwipeRegionWidth if (inOpeningSwipeRegion && !hubOccluded) { isTrackingOpenGesture = true - communalContainerView.dispatchTouchEvent(ev) + dispatchTouchEvent(ev) // Return true regardless of dispatch result as some touches at the start of a // gesture may return false from dispatchTouchEvent. return true @@ -184,7 +187,7 @@ constructor( if (isUp || isCancel) { isTrackingOpenGesture = false } - communalContainerView.dispatchTouchEvent(ev) + dispatchTouchEvent(ev) // Return true regardless of dispatch result as some touches at the start of a gesture // may return false from dispatchTouchEvent. return true @@ -192,4 +195,17 @@ constructor( return false } + + /** + * Dispatches the touch event to the communal container and sends a user activity event to reset + * the screen timeout. + */ + private fun dispatchTouchEvent(ev: MotionEvent) { + communalContainerView.dispatchTouchEvent(ev) + powerManager.userActivity( + SystemClock.uptimeMillis(), + PowerManager.USER_ACTIVITY_EVENT_TOUCH, + 0 + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenHeaderHelper.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenHeaderHelper.kt new file mode 100644 index 000000000000..c74f038ebea4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenHeaderHelper.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2023 The Android Open 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.shade + +import android.content.Context +import com.android.internal.policy.SystemBarUtils +import com.android.systemui.res.R +import javax.inject.Inject +import kotlin.math.max + +class LargeScreenHeaderHelper @Inject constructor(private val context: Context) { + + fun getLargeScreenHeaderHeight(): Int = getLargeScreenHeaderHeight(context) + + companion object { + @JvmStatic + fun getLargeScreenHeaderHeight(context: Context): Int { + val defaultHeight = + context.resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height) + val statusBarHeight = SystemBarUtils.getStatusBarHeight(context) + // Height has to be at least as tall as the status bar, as the status bar height takes + // into account display cutouts. + return max(defaultHeight, statusBarHeight) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 6f4a1e7754f5..aeccf0031419 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -27,6 +27,7 @@ import static com.android.keyguard.KeyguardClockSwitch.SMALL; import static com.android.systemui.Flags.keyguardBottomAreaRefactor; import static com.android.systemui.Flags.migrateClocksToBlueprint; import static com.android.systemui.Flags.predictiveBackAnimateShade; +import static com.android.systemui.Flags.smartspaceRelocateToBottom; import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK; import static com.android.systemui.classifier.Classifier.GENERIC; import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS; @@ -1214,7 +1215,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump .setMaxLengthSeconds(0.4f).build(); mStatusBarMinHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); mStatusBarHeaderHeightKeyguard = Utils.getStatusBarHeaderHeightKeyguard(mView.getContext()); - mClockPositionAlgorithm.loadDimens(mResources); + mClockPositionAlgorithm.loadDimens(mView.getContext(), mResources); mIndicationBottomPadding = mResources.getDimensionPixelSize( R.dimen.keyguard_indication_bottom_padding); int statusbarHeight = SystemBarUtils.getStatusBarHeight(mView.getContext()); @@ -1428,7 +1429,12 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump int index = mView.indexOfChild(mKeyguardBottomArea); mView.removeView(mKeyguardBottomArea); KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea; - setKeyguardBottomArea(mKeyguardBottomAreaViewControllerProvider.get().getView()); + KeyguardBottomAreaViewController keyguardBottomAreaViewController = + mKeyguardBottomAreaViewControllerProvider.get(); + if (smartspaceRelocateToBottom()) { + keyguardBottomAreaViewController.init(); + } + setKeyguardBottomArea(keyguardBottomAreaViewController.getView()); mKeyguardBottomArea.initFrom(oldBottomArea); mView.addView(mKeyguardBottomArea, index); @@ -1751,14 +1757,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } else { layout = mNotificationContainerParent; } - - if (migrateClocksToBlueprint()) { - mKeyguardInteractor.setClockShouldBeCentered(mSplitShadeEnabled && shouldBeCentered); - } else { - mKeyguardStatusViewController.updateAlignment( - layout, mSplitShadeEnabled, shouldBeCentered, animate); - mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered)); - } + mKeyguardStatusViewController.updateAlignment( + layout, mSplitShadeEnabled, shouldBeCentered, animate); + mKeyguardUnfoldTransition.ifPresent(t -> t.setStatusViewCentered(shouldBeCentered)); } private boolean shouldKeyguardStatusViewBeCentered() { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 5fbb60d76fbb..60feb82bf4aa 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -373,7 +373,9 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW boolean onKeyguard = state.statusBarState == StatusBarState.KEYGUARD && !state.keyguardFadingAway && !state.keyguardGoingAway; if (onKeyguard - && mAuthController.isUdfpsEnrolled(mUserInteractor.get().getSelectedUserId())) { + && mAuthController.isOpticalUdfpsEnrolled( + mUserInteractor.get().getSelectedUserId()) + ) { // Requests the max refresh rate (ie: for smooth display). Note: By setting // the preferred refresh rates below, the refresh rate will not override the max // refresh rate in settings (ie: if smooth display is OFF). @@ -892,6 +894,8 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW pw.println(TAG + ":"); pw.println(" mKeyguardMaxRefreshRate=" + mKeyguardMaxRefreshRate); pw.println(" mKeyguardPreferredRefreshRate=" + mKeyguardPreferredRefreshRate); + pw.println(" preferredMinDisplayRefreshRate=" + mLpChanged.preferredMinDisplayRefreshRate); + pw.println(" preferredMaxDisplayRefreshRate=" + mLpChanged.preferredMaxDisplayRefreshRate); pw.println(" mDeferWindowLayoutParams=" + mDeferWindowLayoutParams); pw.println(mCurrentState); if (mWindowRootView != null && mWindowRootView.getViewRootImpl() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java index cde2a62f9ae9..8c852cd04738 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java @@ -31,16 +31,12 @@ import android.view.ViewGroup; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.AuthKeyguardMessageArea; -import com.android.keyguard.KeyguardMessageAreaController; import com.android.keyguard.LockIconViewController; -import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.Dumpable; import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; -import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor; -import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder; -import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel; +import com.android.systemui.bouncer.ui.binder.BouncerViewBinder; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor; @@ -56,8 +52,6 @@ import com.android.systemui.keyguard.shared.model.TransitionState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.keyguard.ui.binder.AlternateBouncerViewBinder; import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies; -import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel; -import com.android.systemui.log.BouncerLogger; import com.android.systemui.res.R; import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener; import com.android.systemui.statusbar.DragDownHelper; @@ -77,7 +71,6 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarViewController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; -import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.time.SystemClock; @@ -183,24 +176,18 @@ public class NotificationShadeWindowViewController implements Dumpable { DumpManager dumpManager, PulsingGestureListener pulsingGestureListener, LockscreenHostedDreamGestureListener lockscreenHostedDreamGestureListener, - KeyguardBouncerViewModel keyguardBouncerViewModel, - KeyguardBouncerComponent.Factory keyguardBouncerComponentFactory, - KeyguardMessageAreaController.Factory messageAreaControllerFactory, KeyguardTransitionInteractor keyguardTransitionInteractor, - PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel, GlanceableHubContainerController glanceableHubContainerController, NotificationLaunchAnimationInteractor notificationLaunchAnimationInteractor, FeatureFlagsClassic featureFlagsClassic, SystemClock clock, - BouncerMessageInteractor bouncerMessageInteractor, - BouncerLogger bouncerLogger, SysUIKeyEventHandler sysUIKeyEventHandler, QuickSettingsController quickSettingsController, PrimaryBouncerInteractor primaryBouncerInteractor, AlternateBouncerInteractor alternateBouncerInteractor, - SelectedUserInteractor selectedUserInteractor, Lazy<JavaAdapter> javaAdapter, - Lazy<AlternateBouncerDependencies> alternateBouncerDependencies) { + Lazy<AlternateBouncerDependencies> alternateBouncerDependencies, + BouncerViewBinder bouncerViewBinder) { mLockscreenShadeTransitionController = transitionController; mFalsingCollector = falsingCollector; mStatusBarStateController = statusBarStateController; @@ -234,15 +221,7 @@ public class NotificationShadeWindowViewController implements Dumpable { // This view is not part of the newly inflated expanded status bar. mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container); mDisableSubpixelTextTransitionListener = new DisableSubpixelTextTransitionListener(mView); - KeyguardBouncerViewBinder.bind( - mView.findViewById(R.id.keyguard_bouncer_container), - keyguardBouncerViewModel, - primaryBouncerToGoneTransitionViewModel, - keyguardBouncerComponentFactory, - messageAreaControllerFactory, - bouncerMessageInteractor, - bouncerLogger, - selectedUserInteractor); + bouncerViewBinder.bind(mView.findViewById(R.id.keyguard_bouncer_container)); if (DeviceEntryUdfpsRefactor.isEnabled()) { AlternateBouncerViewBinder.bind( diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index 9c8a286b2918..84cad1d16d73 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -27,6 +27,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.lifecycle.lifecycleScope +import com.android.systemui.Flags.centralizedStatusBarDimensRefactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.flags.FeatureFlags @@ -47,10 +48,11 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.LargeScreenUtils import com.android.systemui.util.ViewController import com.android.systemui.util.concurrency.DelayableExecutor -import kotlinx.coroutines.launch +import dagger.Lazy import java.util.function.Consumer import javax.inject.Inject import kotlin.reflect.KMutableProperty0 +import kotlinx.coroutines.launch @VisibleForTesting internal const val INSET_DEBOUNCE_MILLIS = 500L @@ -67,7 +69,8 @@ class NotificationsQSContainerController @Inject constructor( private val featureFlags: FeatureFlags, private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController, - private val splitShadeStateController: SplitShadeStateController + private val splitShadeStateController: SplitShadeStateController, + private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, ) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController { private var splitShadeEnabled = false @@ -186,7 +189,11 @@ class NotificationsQSContainerController @Inject constructor( } private fun calculateLargeShadeHeaderHeight(): Int { - return resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height) + return if (centralizedStatusBarDimensRefactor()) { + largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + } else { + resources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height) + } } private fun calculateShadeHeaderHeight(): Int { diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index 1dff99d53078..f3e9c7503626 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -20,6 +20,7 @@ package com.android.systemui.shade; import static android.view.WindowInsets.Type.ime; import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE; +import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor; import static com.android.systemui.classifier.Classifier.QS_COLLAPSE; import static com.android.systemui.shade.NotificationPanelViewController.COUNTER_PANEL_OPEN_QS; import static com.android.systemui.shade.NotificationPanelViewController.FLING_COLLAPSE; @@ -126,6 +127,7 @@ public class QuickSettingsController implements Dumpable { private final Lazy<NotificationPanelViewController> mPanelViewControllerLazy; private final NotificationPanelView mPanelView; + private final Lazy<LargeScreenHeaderHelper> mLargeScreenHeaderHelperLazy; private final KeyguardStatusBarView mKeyguardStatusBar; private final FrameLayout mQsFrame; @@ -344,10 +346,12 @@ public class QuickSettingsController implements Dumpable { ActiveNotificationsInteractor activeNotificationsInteractor, JavaAdapter javaAdapter, CastController castController, - SplitShadeStateController splitShadeStateController + SplitShadeStateController splitShadeStateController, + Lazy<LargeScreenHeaderHelper> largeScreenHeaderHelperLazy ) { mPanelViewControllerLazy = panelViewControllerLazy; mPanelView = panelView; + mLargeScreenHeaderHelperLazy = largeScreenHeaderHelperLazy; mQsFrame = mPanelView.findViewById(R.id.qs_frame); mKeyguardStatusBar = mPanelView.findViewById(R.id.keyguard_header); mResources = mPanelView.getResources(); @@ -449,7 +453,10 @@ public class QuickSettingsController implements Dumpable { mUseLargeScreenShadeHeader = LargeScreenUtils.shouldUseLargeScreenShadeHeader(mPanelView.getResources()); mLargeScreenShadeHeaderHeight = - mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height); + centralizedStatusBarDimensRefactor() + ? mLargeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + : mResources.getDimensionPixelSize( + R.dimen.large_screen_shade_header_height); int topMargin = mUseLargeScreenShadeHeader ? mLargeScreenShadeHeaderHeight : mResources.getDimensionPixelSize(R.dimen.notification_panel_margin_top); mShadeHeaderController.setLargeScreenActive(mUseLargeScreenShadeHeader); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt index 2460a3314be5..a66bacd237be 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt @@ -38,6 +38,7 @@ import androidx.core.view.doOnLayout import com.android.app.animation.Interpolators import com.android.settingslib.Utils import com.android.systemui.Dumpable +import com.android.systemui.Flags.centralizedStatusBarDimensRefactor import com.android.systemui.animation.ShadeInterpolation import com.android.systemui.battery.BatteryMeterView import com.android.systemui.battery.BatteryMeterViewController @@ -432,6 +433,9 @@ constructor( changes += combinedShadeHeadersConstraintManager.emptyCutoutConstraints() } + if (centralizedStatusBarDimensRefactor()) { + view.setPadding(view.paddingLeft, sbInsets.top, view.paddingRight, view.paddingBottom) + } view.updateAllConstraints(changes) updateBatteryMode() } diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt index 7a340d2f0268..6407b5a4d16c 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt @@ -25,8 +25,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository +import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository import com.android.systemui.user.domain.interactor.UserSwitcherInteractor import javax.inject.Inject import kotlinx.coroutines.CoroutineScope @@ -94,7 +94,7 @@ constructor( disableFlagsRepository.disableFlags, isShadeEnabled, keyguardRepository.isDozing, - userSetupRepository.isUserSetupFlow, + userSetupRepository.isUserSetUp, deviceProvisioningRepository.isDeviceProvisioned, ) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned -> isDeviceProvisioned && diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index 39b7930ed386..6e8507422fbe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -253,6 +253,8 @@ constructor( initialHeight: Int? = null ) : View(context, attrs) { + private val logString = this::class.simpleName!! + "@" + hashCode() + /** Listener that is called if the scrim's opaqueness changes */ var isScrimOpaqueChangedListener: Consumer<Boolean>? = null @@ -267,13 +269,13 @@ constructor( if (field != value) { field = value if (value <= 0.0f || value >= 1.0f) { - scrimLogger?.d(TAG, "revealAmount", "$value on ${logString()}") + scrimLogger?.d(TAG, "revealAmount", "$value on $logString") } revealEffect.setRevealAmountOnScrim(value, this) updateScrimOpaque() Trace.traceCounter( Trace.TRACE_TAG_APP, - "light_reveal_amount", + "light_reveal_amount $logString", (field * 100).toInt() ) invalidate() @@ -290,7 +292,7 @@ constructor( field = value revealEffect.setRevealAmountOnScrim(revealAmount, this) - scrimLogger?.d(TAG, "revealEffect", "$value on ${logString()}") + scrimLogger?.d(TAG, "revealEffect", "$value on $logString") invalidate() } } @@ -350,7 +352,7 @@ constructor( if (field != value) { field = value isScrimOpaqueChangedListener?.accept(field) - scrimLogger?.d(TAG, "isScrimOpaque", "$value on ${logString()}") + scrimLogger?.d(TAG, "isScrimOpaque", "$value on $logString") } } @@ -368,13 +370,13 @@ constructor( override fun setAlpha(alpha: Float) { super.setAlpha(alpha) - scrimLogger?.d(TAG, "alpha", "$alpha on ${logString()}") + scrimLogger?.d(TAG, "alpha", "$alpha on $logString") updateScrimOpaque() } override fun setVisibility(visibility: Int) { super.setVisibility(visibility) - scrimLogger?.d(TAG, "visibility", "$visibility on ${logString()}") + scrimLogger?.d(TAG, "visibility", "$visibility on $logString") updateScrimOpaque() } @@ -467,8 +469,4 @@ constructor( PorterDuff.Mode.MULTIPLY ) } - - private fun logString(): String { - return this::class.simpleName!! + "@" + hashCode() - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt index 2438298f6a6e..7f8be1cc7e55 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt @@ -22,6 +22,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver +import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.media.controls.ui.MediaHierarchyManager import com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll import com.android.systemui.plugins.ActivityStarter @@ -888,6 +889,9 @@ class DragDownHelper( isDraggingDown = false isTrackpadReverseScroll = false shadeRepository.setLegacyLockscreenShadeTracking(false) + if (KeyguardShadeMigrationNssl.isEnabled) { + return true + } } else { stopDragging() return false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 9b8dd0b75a24..24ac70e63e46 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -15,17 +15,17 @@ */ package com.android.systemui.statusbar; +import static android.app.Flags.keyguardPrivateNotifications; import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; +import static android.os.Flags.allowPrivateProfile; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_NULL; import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import static android.provider.Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS; -import static android.app.Flags.keyguardPrivateNotifications; -import static android.os.Flags.allowPrivateProfile; import static com.android.systemui.DejankUtils.whitelistIpcs; @@ -42,9 +42,8 @@ import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.UserInfo; import android.database.ContentObserver; +import android.database.ExecutorContentObserver; import android.net.Uri; -import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.UserHandle; import android.os.UserManager; @@ -79,17 +78,17 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.ListenerSet; import com.android.systemui.util.settings.SecureSettings; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.concurrent.Executor; import java.util.Objects; +import java.util.concurrent.Executor; import javax.inject.Inject; -import dagger.Lazy; - /** * Handles keeping track of the current user, profiles, and various things related to hiding * contents, redacting notifications, and the lockscreen. @@ -228,7 +227,7 @@ public class NotificationLockscreenUserManagerImpl implements updateCurrentProfilesCache(); if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL); - mBackgroundHandler.post(() -> { + mBackgroundExecutor.execute(() -> { initValuesForUser(userId); }); } @@ -289,8 +288,7 @@ public class NotificationLockscreenUserManagerImpl implements }; protected final Context mContext; - private final Handler mMainHandler; - private final Handler mBackgroundHandler; + private final Executor mMainExecutor; private final Executor mBackgroundExecutor; /** The current user and its profiles (possibly including a communal profile). */ protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>(); @@ -313,8 +311,7 @@ public class NotificationLockscreenUserManagerImpl implements Lazy<OverviewProxyService> overviewProxyServiceLazy, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, - @Main Handler mainHandler, - @Background Handler backgroundHandler, + @Main Executor mainExecutor, @Background Executor backgroundExecutor, DeviceProvisionedController deviceProvisionedController, KeyguardStateController keyguardStateController, @@ -323,8 +320,7 @@ public class NotificationLockscreenUserManagerImpl implements LockPatternUtils lockPatternUtils, FeatureFlagsClassic featureFlags) { mContext = context; - mMainHandler = mainHandler; - mBackgroundHandler = backgroundHandler; + mMainExecutor = mainExecutor; mBackgroundExecutor = backgroundExecutor; mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; @@ -362,10 +358,10 @@ public class NotificationLockscreenUserManagerImpl implements } private void init() { - mLockscreenSettingsObserver = new ContentObserver( + mLockscreenSettingsObserver = new ExecutorContentObserver( mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD) - ? mBackgroundHandler - : mMainHandler) { + ? mBackgroundExecutor + : mMainExecutor) { @Override public void onChange(boolean selfChange, Collection<Uri> uris, int flags) { @@ -412,7 +408,7 @@ public class NotificationLockscreenUserManagerImpl implements } }; - mSettingsObserver = new ContentObserver(mMainHandler) { + mSettingsObserver = new ExecutorContentObserver(mMainExecutor) { @Override public void onChange(boolean selfChange) { updateLockscreenNotificationSetting(); @@ -468,14 +464,14 @@ public class NotificationLockscreenUserManagerImpl implements mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null, Context.RECEIVER_EXPORTED_UNAUDITED); - mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler)); + mUserTracker.addCallback(mUserChangedCallback, mMainExecutor); mCurrentUserId = mUserTracker.getUserId(); // in case we reg'd receiver too late updateCurrentProfilesCache(); if (mFeatureFlags.isEnabled(Flags.NOTIF_LS_BACKGROUND_THREAD)) { // Set up - mBackgroundHandler.post(() -> { + mBackgroundExecutor.execute(() -> { @SuppressLint("MissingPermission") List<UserInfo> users = mUserManager.getUsers(); for (int i = users.size() - 1; i >= 0; i--) { initValuesForUser(users.get(i).id); @@ -796,7 +792,7 @@ public class NotificationLockscreenUserManagerImpl implements } } } - mMainHandler.post(() -> { + mMainExecutor.execute(() -> { for (UserChangedListener listener : mListeners) { listener.onCurrentProfilesChanged(mCurrentProfiles); } @@ -895,7 +891,7 @@ public class NotificationLockscreenUserManagerImpl implements private void notifyNotificationStateChanged() { if (!Looper.getMainLooper().isCurrentThread()) { - mMainHandler.post(() -> { + mMainExecutor.execute(() -> { for (NotificationStateChangedListener listener : mNotifStateChangedListeners) { listener.onNotificationStateChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt index 29d53fc15e8b..9f878b241d73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.data import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule +import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule import dagger.Module @@ -24,6 +25,7 @@ import dagger.Module includes = [ KeyguardStatusBarRepositoryModule::class, + RemoteInputRepositoryModule::class, StatusBarModeRepositoryModule::class, StatusBarPhoneDataLayerModule::class ] diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt new file mode 100644 index 000000000000..c0302bc348b6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.data.repository + +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.NotificationRemoteInputManager +import com.android.systemui.statusbar.RemoteInputController +import dagger.Binds +import dagger.Module +import javax.inject.Inject +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow + +/** + * Repository used for tracking the state of notification remote input (e.g. when the user presses + * "reply" on a notification and the keyboard opens). + */ +interface RemoteInputRepository { + /** Whether remote input is currently active for any notification. */ + val isRemoteInputActive: Flow<Boolean> +} + +@SysUISingleton +class RemoteInputRepositoryImpl +@Inject +constructor( + private val notificationRemoteInputManager: NotificationRemoteInputManager, +) : RemoteInputRepository { + override val isRemoteInputActive: Flow<Boolean> = conflatedCallbackFlow { + trySend(false) // initial value is false + val callback = + object : RemoteInputController.Callback { + override fun onRemoteInputActive(active: Boolean) { + trySend(active) + } + } + notificationRemoteInputManager.addControllerCallback(callback) + awaitClose { notificationRemoteInputManager.removeControllerCallback(callback) } + } +} + +@Module +interface RemoteInputRepositoryModule { + @Binds fun bindImpl(impl: RemoteInputRepositoryImpl): RemoteInputRepository +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt new file mode 100644 index 000000000000..68f727b046c0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.data.repository.RemoteInputRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +/** + * Interactor used for business logic pertaining to the notification remote input (e.g. when the + * user presses "reply" on a notification and the keyboard opens). + */ +@SysUISingleton +class RemoteInputInteractor @Inject constructor(remoteInputRepository: RemoteInputRepository) { + /** Is remote input currently active for a notification? */ + val isRemoteInputActive: Flow<Boolean> = remoteInputRepository.isRemoteInputActive +} 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 31ca106d2bc9..e200e65a9f4a 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 @@ -273,12 +273,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private final RefactorFlag mInlineReplyAnimation = RefactorFlag.forView(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION); - private static final boolean mSimulateSlowMeasure = Compile.IS_DEBUG && RefactorFlag.forView( - Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled(); + private static boolean shouldSimulateSlowMeasure() { + return Compile.IS_DEBUG && RefactorFlag.forView( + Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled(); + } + private static final String SLOW_MEASURE_SIMULATE_DELAY_PROPERTY = "persist.notifications.extra_measure_delay_ms"; - private static final int SLOW_MEASURE_SIMULATE_DELAY_MS = mSimulateSlowMeasure ? - SystemProperties.getInt(SLOW_MEASURE_SIMULATE_DELAY_PROPERTY, 150) : 0; + private static final int SLOW_MEASURE_SIMULATE_DELAY_MS = + SystemProperties.getInt(SLOW_MEASURE_SIMULATE_DELAY_PROPERTY, 150); // Listener will be called when receiving a long click event. // Use #setLongPressPosition to optionally assign positional data with the long press. @@ -1886,7 +1889,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (Compile.IS_DEBUG && mSimulateSlowMeasure) { + if (shouldSimulateSlowMeasure()) { simulateExtraMeasureDelay(); } Trace.endSection(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 6528cef3dec1..a1718b9fbb02 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -37,6 +37,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -45,8 +46,8 @@ import androidx.annotation.MainThread; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; -import com.android.systemui.res.R; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; +import com.android.systemui.res.R; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; @@ -898,6 +899,7 @@ public class NotificationContentView extends FrameLayout implements Notification // forceUpdateVisibilities cancels outstanding animations without updating the // mAnimationStartVisibleType. Do so here instead. mAnimationStartVisibleType = VISIBLE_TYPE_NONE; + notifySubtreeForAccessibilityContentChange(); } private void fireExpandedVisibleListenerIfVisible() { @@ -980,6 +982,7 @@ public class NotificationContentView extends FrameLayout implements Notification // updateViewVisibilities cancels outstanding animations without updating the // mAnimationStartVisibleType. Do so here instead. mAnimationStartVisibleType = VISIBLE_TYPE_NONE; + notifySubtreeForAccessibilityContentChange(); } private void updateViewVisibility(int visibleType, int type, View view, @@ -1029,6 +1032,7 @@ public class NotificationContentView extends FrameLayout implements Notification hiddenView.setVisible(false); } mAnimationStartVisibleType = VISIBLE_TYPE_NONE; + notifySubtreeForAccessibilityContentChange(); } }); fireExpandedVisibleListenerIfVisible(); @@ -1049,6 +1053,22 @@ public class NotificationContentView extends FrameLayout implements Notification } } + @Override + public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) { + if (isAnimatingVisibleType()) { + // Don't send A11y events while animating to reduce Jank. + return; + } + super.notifySubtreeAccessibilityStateChanged(child, source, changeType); + } + + private void notifySubtreeForAccessibilityContentChange() { + if (mParent != null) { + mParent.notifySubtreeAccessibilityStateChanged(this, this, + AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); + } + } + /** * @param visibleType one of the static enum types in this view * @return the corresponding transformable view according to the given visible type @@ -2277,6 +2297,11 @@ public class NotificationContentView extends FrameLayout implements Notification mHeadsUpWrapper = headsUpWrapper; } + @VisibleForTesting + protected void setAnimationStartVisibleType(int animationStartVisibleType) { + mAnimationStartVisibleType = animationStartVisibleType; + } + @Override protected void dispatchDraw(Canvas canvas) { try { 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 abc04b87f831..a30c29456b3b 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 @@ -69,6 +69,7 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FeatureFlagsClassic; import com.android.systemui.flags.Flags; import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository; +import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl; import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.keyguard.shared.model.TransitionStep; import com.android.systemui.media.controls.ui.KeyguardMediaController; @@ -1957,18 +1958,34 @@ public class NotificationStackScrollLayoutController implements Dumpable { mView.dispatchDownEventToScroller(ev); } } - boolean scrollerWantsIt = false; - if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping() - && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) { - scrollerWantsIt = mView.onScrollTouch(ev); - } boolean horizontalSwipeWantsIt = false; - if (mLongPressedView == null && !mView.isBeingDragged() - && !expandingNotification - && !mView.getExpandedInThisMotion() - && !onlyScrollingInThisMotion - && !mView.getDisallowDismissInThisMotion()) { - horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); + boolean scrollerWantsIt = false; + if (KeyguardShadeMigrationNssl.isEnabled()) { + // Reverse the order relative to the else statement. onScrollTouch will reset on an + // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes. + if (mLongPressedView == null && !mView.isBeingDragged() + && !expandingNotification + && !mView.getExpandedInThisMotion() + && !onlyScrollingInThisMotion + && !mView.getDisallowDismissInThisMotion()) { + horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); + } + if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping() + && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) { + scrollerWantsIt = mView.onScrollTouch(ev); + } + } else { + if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping() + && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) { + scrollerWantsIt = mView.onScrollTouch(ev); + } + if (mLongPressedView == null && !mView.isBeingDragged() + && !expandingNotification + && !mView.getExpandedInThisMotion() + && !onlyScrollingInThisMotion + && !mView.getDisallowDismissInThisMotion()) { + horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev); + } } // Check if we need to clear any snooze leavebehinds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt index 625fdc1c12f8..4b8fb1e5a0ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractor.kt @@ -18,12 +18,15 @@ package com.android.systemui.statusbar.notification.stack.domain.interactor import android.content.Context +import com.android.systemui.Flags.centralizedStatusBarDimensRefactor import com.android.systemui.common.ui.data.repository.ConfigurationRepository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.res.R +import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.statusbar.policy.SplitShadeStateController +import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -45,6 +48,7 @@ constructor( private val splitShadeStateController: SplitShadeStateController, keyguardInteractor: KeyguardInteractor, deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>, ) { private val _topPosition = MutableStateFlow(0f) @@ -72,7 +76,11 @@ constructor( getDimensionPixelSize(R.dimen.notification_panel_margin_bottom), marginTop = getDimensionPixelSize(R.dimen.notification_panel_margin_top), marginTopLargeScreen = - getDimensionPixelSize(R.dimen.large_screen_shade_header_height), + if (centralizedStatusBarDimensRefactor()) { + largeScreenHeaderHelperLazy.get().getLargeScreenHeaderHeight() + } else { + getDimensionPixelSize(R.dimen.large_screen_shade_header_height) + }, keyguardSplitShadeTopMargin = getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin), ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt index 0bad47ecb2ae..8a45ec15b627 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt @@ -18,12 +18,23 @@ package com.android.systemui.statusbar.phone import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.Flags.smartspaceRelocateToBottom +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import com.android.systemui.res.R +import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController import com.android.systemui.util.ViewController import javax.inject.Inject class KeyguardBottomAreaViewController - @Inject constructor(view: KeyguardBottomAreaView, featureFlags: FeatureFlagsClassic) : - ViewController<KeyguardBottomAreaView> (view) { + @Inject constructor( + view: KeyguardBottomAreaView, + private val smartspaceController: LockscreenSmartspaceController, + featureFlags: FeatureFlagsClassic +) : ViewController<KeyguardBottomAreaView> (view) { + + private var smartspaceView: View? = null init { view.setIsLockscreenLandscapeEnabled( @@ -31,6 +42,14 @@ class KeyguardBottomAreaViewController } override fun onViewAttached() { + if (!smartspaceRelocateToBottom() || !smartspaceController.isEnabled()) { + return + } + + val ambientIndicationArea = mView.findViewById<View>(R.id.ambient_indication_container) + ambientIndicationArea?.visibility = View.GONE + + addSmartspaceView() } override fun onViewDetached() { @@ -40,4 +59,24 @@ class KeyguardBottomAreaViewController // TODO: remove this method. return mView } + + private fun addSmartspaceView() { + if (!smartspaceRelocateToBottom()) { + return + } + + val smartspaceContainer = mView.findViewById<View>(R.id.smartspace_container) + smartspaceContainer!!.visibility = View.VISIBLE + + smartspaceView = smartspaceController.buildAndConnectView(smartspaceContainer as ViewGroup) + val lp = LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + (smartspaceContainer as ViewGroup).addView(smartspaceView, 0, lp) + val startPadding = context.resources.getDimensionPixelSize( + R.dimen.below_clock_padding_start) + val endPadding = context.resources.getDimensionPixelSize( + R.dimen.below_clock_padding_end) + smartspaceView?.setPaddingRelative(startPadding, 0, endPadding, 0) +// mKeyguardUnlockAnimationController.lockscreenSmartspace = smartspaceView + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index 0a03af7d9387..ca3e3c629619 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -16,10 +16,12 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInScale; import static com.android.systemui.statusbar.notification.NotificationUtils.interpolate; +import android.content.Context; import android.content.res.Resources; import android.util.MathUtils; @@ -30,6 +32,7 @@ import com.android.systemui.log.LogBuffer; import com.android.systemui.log.core.Logger; import com.android.systemui.log.dagger.KeyguardClockLog; import com.android.systemui.res.R; +import com.android.systemui.shade.LargeScreenHeaderHelper; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherListView; @@ -160,14 +163,14 @@ public class KeyguardClockPositionAlgorithm { mLogger = new Logger(logBuffer, TAG); } - /** - * Refreshes the dimension values. - */ - public void loadDimens(Resources res) { - mStatusViewBottomMargin = res.getDimensionPixelSize( - R.dimen.keyguard_status_view_bottom_margin); + /** Refreshes the dimension values. */ + public void loadDimens(Context context, Resources res) { + mStatusViewBottomMargin = + res.getDimensionPixelSize(R.dimen.keyguard_status_view_bottom_margin); mSplitShadeTopNotificationsMargin = - res.getDimensionPixelSize(R.dimen.large_screen_shade_header_height); + centralizedStatusBarDimensRefactor() + ? LargeScreenHeaderHelper.getLargeScreenHeaderHeight(context) + : res.getDimensionPixelSize(R.dimen.large_screen_shade_header_height); mSplitShadeTargetTopMargin = res.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 7cc08887ae52..769145923886 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.Flags.centralizedStatusBarDimensRefactor; import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection; import static com.android.systemui.util.Utils.getStatusBarHeaderHeightKeyguard; @@ -130,6 +131,9 @@ public class KeyguardStatusBarView extends RelativeLayout { mUserSwitcherContainer = findViewById(R.id.user_switcher_container); mIsPrivacyDotEnabled = mContext.getResources().getBoolean(R.bool.config_enablePrivacyDot); loadDimens(); + if (!centralizedStatusBarDimensRefactor()) { + setGravity(Gravity.CENTER_VERTICAL); + } } /** @@ -307,7 +311,8 @@ public class KeyguardStatusBarView extends RelativeLayout { final int minRight = (!isLayoutRtl() && mIsPrivacyDotEnabled) ? Math.max(mMinDotWidth, mPadding.right) : mPadding.right; - setPadding(minLeft, waterfallTop, minRight, 0); + int top = centralizedStatusBarDimensRefactor() ? waterfallTop + mPadding.top : waterfallTop; + setPadding(minLeft, top, minRight, 0); } private boolean updateLayoutParamsNoCutout() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index 30a445f7ce4a..703b3c65029a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -118,15 +118,25 @@ public class StatusBarSignalPolicy implements SignalCallback, private void updateVpn() { boolean vpnVisible = mSecurityController.isVpnEnabled(); - int vpnIconId = currentVpnIconId(mSecurityController.isVpnBranded()); + int vpnIconId = currentVpnIconId( + mSecurityController.isVpnBranded(), + mSecurityController.isVpnValidated()); mIconController.setIcon(mSlotVpn, vpnIconId, mContext.getResources().getString(R.string.accessibility_vpn_on)); mIconController.setIconVisibility(mSlotVpn, vpnVisible); } - private int currentVpnIconId(boolean isBranded) { - return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic; + private int currentVpnIconId(boolean isBranded, boolean isValidated) { + if (isBranded) { + return isValidated + ? R.drawable.stat_sys_branded_vpn + : R.drawable.stat_sys_no_internet_branded_vpn; + } else { + return isValidated + ? R.drawable.stat_sys_vpn_ic + : R.drawable.stat_sys_no_internet_vpn_ic; + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt index 89a2fb78635b..e309c32df64e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt @@ -34,8 +34,6 @@ import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistr import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher -import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepositoryImpl import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter @@ -62,6 +60,8 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRep import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryViaTrackerLib import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl +import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository +import com.android.systemui.statusbar.policy.data.repository.UserSetupRepositoryImpl import dagger.Binds import dagger.Module import dagger.Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt index 39135c70788d..d555c47f4da2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt @@ -32,9 +32,9 @@ import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository +import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository import com.android.systemui.util.CarrierConfigTracker import java.lang.ref.WeakReference import javax.inject.Inject @@ -105,7 +105,7 @@ interface MobileIconsInteractor { val isDefaultConnectionFailed: StateFlow<Boolean> /** True once the user has been set up */ - val isUserSetup: StateFlow<Boolean> + val isUserSetUp: StateFlow<Boolean> /** True if we're configured to force-hide the mobile icons and false otherwise. */ val isForceHidden: Flow<Boolean> @@ -362,7 +362,7 @@ constructor( ) .stateIn(scope, SharingStarted.WhileSubscribed(), false) - override val isUserSetup: StateFlow<Boolean> = userSetupRepo.isUserSetupFlow + override val isUserSetUp: StateFlow<Boolean> = userSetupRepo.isUserSetUp override val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt index 8fc8b2f31366..de46a5ed99d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt @@ -19,7 +19,7 @@ package com.android.systemui.statusbar.pipeline.satellite.data.prod import android.os.OutcomeReceiver import android.telephony.satellite.NtnSignalStrengthCallback import android.telephony.satellite.SatelliteManager -import android.telephony.satellite.SatelliteStateCallback +import android.telephony.satellite.SatelliteModemStateCallback import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -180,7 +180,7 @@ constructor( // By using the SupportedSatelliteManager here, we expect registration never to fail private fun connectionStateFlow(sm: SupportedSatelliteManager): Flow<SatelliteConnectionState> = conflatedCallbackFlow { - val cb = SatelliteStateCallback { state -> + val cb = SatelliteModemStateCallback { state -> trySend(SatelliteConnectionState.fromModemState(state)) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java index 3be14bc867a1..10bf0680b567 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java @@ -48,6 +48,8 @@ public interface SecurityController extends CallbackController<SecurityControlle boolean isNetworkLoggingEnabled(); boolean isVpnEnabled(); boolean isVpnRestricted(); + /** Whether the VPN network is validated. */ + boolean isVpnValidated(); /** Whether the VPN app should use branded VPN iconography. */ boolean isVpnBranded(); String getPrimaryVpnName(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index 5d69f367d77e..9f4a90658b2e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -15,6 +15,9 @@ */ package com.android.systemui.statusbar.policy; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; + import android.annotation.Nullable; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; @@ -32,7 +35,9 @@ import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.VpnManager; import android.os.Handler; @@ -76,7 +81,10 @@ public class SecurityControllerImpl implements SecurityController { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final NetworkRequest REQUEST = - new NetworkRequest.Builder().clearCapabilities().build(); + new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(TRANSPORT_VPN) + .build(); private static final int NO_NETWORK = -1; private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED"; @@ -99,6 +107,8 @@ public class SecurityControllerImpl implements SecurityController { private SparseArray<VpnConfig> mCurrentVpns = new SparseArray<>(); private int mCurrentUserId; private int mVpnUserId; + @GuardedBy("mNetworkProperties") + private final SparseArray<NetworkProperties> mNetworkProperties = new SparseArray<>(); // Key: userId, Value: whether the user has CACerts installed // Needs to be cached here since the query has to be asynchronous @@ -162,6 +172,21 @@ public class SecurityControllerImpl implements SecurityController { pw.print(mCurrentVpns.valueAt(i).user); } pw.println("}"); + pw.print(" mNetworkProperties={"); + synchronized (mNetworkProperties) { + for (int i = 0; i < mNetworkProperties.size(); ++i) { + if (i > 0) { + pw.print(", "); + } + pw.print(mNetworkProperties.keyAt(i)); + pw.print("={"); + pw.print(mNetworkProperties.valueAt(i).interfaceName); + pw.print(", "); + pw.print(mNetworkProperties.valueAt(i).validated); + pw.print("}"); + } + } + pw.println("}"); } @Override @@ -304,6 +329,26 @@ public class SecurityControllerImpl implements SecurityController { } @Override + public boolean isVpnValidated() { + // Prioritize reporting the network status of the parent user. + final VpnConfig primaryVpnConfig = mCurrentVpns.get(mVpnUserId); + if (primaryVpnConfig != null) { + return getVpnValidationStatus(primaryVpnConfig); + } + // Identify any Unvalidated status in each active VPN network within other profiles. + for (int profileId : mUserManager.getEnabledProfileIds(mVpnUserId)) { + final VpnConfig vpnConfig = mCurrentVpns.get(profileId); + if (vpnConfig == null) { + continue; + } + if (!getVpnValidationStatus(vpnConfig)) { + return false; + } + } + return true; + } + + @Override public boolean hasCACertInCurrentUser() { Boolean hasCACerts = mHasCACerts.get(mCurrentUserId); return hasCACerts != null && hasCACerts.booleanValue(); @@ -493,11 +538,74 @@ public class SecurityControllerImpl implements SecurityController { @Override public void onLost(Network network) { if (DEBUG) Log.d(TAG, "onLost " + network.getNetId()); + synchronized (mNetworkProperties) { + mNetworkProperties.delete(network.getNetId()); + } updateState(); fireCallbacks(); }; + + + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + if (DEBUG) Log.d(TAG, "onCapabilitiesChanged " + network.getNetId()); + final NetworkProperties properties; + synchronized (mNetworkProperties) { + properties = mNetworkProperties.get(network.getNetId()); + } + // When a new network appears, the system first notifies the application about + // its capabilities through onCapabilitiesChanged. This initial notification + // will be skipped because the interface information is included in the + // subsequent onLinkPropertiesChanged call. After validating the network, the + // system might send another onCapabilitiesChanged notification if the network + // becomes validated. + if (properties == null) { + return; + } + final boolean validated = nc.hasCapability(NET_CAPABILITY_VALIDATED); + if (properties.validated != validated) { + properties.validated = validated; + fireCallbacks(); + } + } + + @Override + public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { + if (DEBUG) Log.d(TAG, "onLinkPropertiesChanged " + network.getNetId()); + final String interfaceName = linkProperties.getInterfaceName(); + if (interfaceName == null) { + Log.w(TAG, "onLinkPropertiesChanged event with null interface"); + return; + } + synchronized (mNetworkProperties) { + final NetworkProperties properties = mNetworkProperties.get(network.getNetId()); + if (properties == null) { + mNetworkProperties.put( + network.getNetId(), + new NetworkProperties(interfaceName, false)); + } else { + properties.interfaceName = interfaceName; + } + } + } }; + /** + * Retrieve the validation status of the VPN network associated with the given VpnConfig. + */ + private boolean getVpnValidationStatus(@NonNull VpnConfig vpnConfig) { + synchronized (mNetworkProperties) { + // Find the network has the same interface as the VpnConfig + for (int i = 0; i < mNetworkProperties.size(); ++i) { + if (mNetworkProperties.valueAt(i).interfaceName.equals(vpnConfig.interfaze)) { + return mNetworkProperties.valueAt(i).validated; + } + } + } + // If no matching network is found, consider it validated. + return true; + } + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) { @@ -508,4 +616,17 @@ public class SecurityControllerImpl implements SecurityController { } } }; + + /** + * A data class to hold specific Network properties received through the NetworkCallback. + */ + private static class NetworkProperties { + public String interfaceName; + public boolean validated; + + NetworkProperties(@NonNull String interfaceName, boolean validated) { + this.interfaceName = interfaceName; + this.validated = validated; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt index 91886bb121d5..2a0812b8ec8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.mobile.data.repository +package com.android.systemui.statusbar.policy.data.repository import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton @@ -34,15 +34,14 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext /** - * Repository to observe the state of [DeviceProvisionedController.isUserSetup]. This information - * can change some policy related to display + * Repository to observe whether the user has completed the setup steps. This information can change + * some policy related to display. */ interface UserSetupRepository { - /** Observable tracking [DeviceProvisionedController.isUserSetup] */ - val isUserSetupFlow: StateFlow<Boolean> + /** Whether the user has completed the setup steps. */ + val isUserSetUp: StateFlow<Boolean> } -@Suppress("EXPERIMENTAL_IS_NOT_ENABLED") @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class UserSetupRepositoryImpl @@ -52,8 +51,7 @@ constructor( @Background private val bgDispatcher: CoroutineDispatcher, @Application scope: CoroutineScope, ) : UserSetupRepository { - /** State flow that tracks [DeviceProvisionedController.isUserSetup] */ - override val isUserSetupFlow: StateFlow<Boolean> = + override val isUserSetUp: StateFlow<Boolean> = conflatedCallbackFlow { val callback = object : DeviceProvisionedController.DeviceProvisionedListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt new file mode 100644 index 000000000000..ca36e392b563 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy.domain.interactor + +import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +class UserSetupInteractor @Inject constructor(repository: UserSetupRepository) { + /** Whether the user has completed the setup steps. */ + val isUserSetUp: Flow<Boolean> = repository.isUserSetUp +} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java deleted file mode 100644 index 8d8599900530..000000000000 --- a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.systemui.tuner; - -import android.os.Bundle; - -import androidx.preference.PreferenceFragment; - -import com.android.systemui.res.R; -import com.android.tools.r8.keepanno.annotations.KeepTarget; -import com.android.tools.r8.keepanno.annotations.UsesReflection; - -public class OtherPrefs extends PreferenceFragment { - // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so - // explicitly declare references per usage in `R.xml.other_settings`. See b/120445169. - @UsesReflection(@KeepTarget(classConstant = PowerNotificationControlsFragment.class)) - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - addPreferencesFromResource(R.xml.other_settings); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java deleted file mode 100644 index ce1a2e9b329c..000000000000 --- a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2016, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.systemui.tuner; - -import android.annotation.Nullable; -import android.app.Fragment; -import android.os.Bundle; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Switch; -import android.widget.TextView; - -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.res.R; - -public class PowerNotificationControlsFragment extends Fragment { - - private static final String KEY_SHOW_PNC = "show_importance_slider"; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.power_notification_controls_settings, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - final View switchBar = view.findViewById(R.id.switch_bar); - final Switch switchWidget = (Switch) switchBar.findViewById(android.R.id.switch_widget); - final TextView switchText = (TextView) switchBar.findViewById(R.id.switch_text); - switchWidget.setChecked(isEnabled()); - switchText.setText(isEnabled() - ? getString(R.string.switch_bar_on) - : getString(R.string.switch_bar_off)); - - switchWidget.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - boolean newState = !isEnabled(); - MetricsLogger.action(getContext(), - MetricsEvent.ACTION_TUNER_POWER_NOTIFICATION_CONTROLS, newState); - Settings.Secure.putInt(getContext().getContentResolver(), - KEY_SHOW_PNC, newState ? 1 : 0); - switchWidget.setChecked(newState); - switchText.setText(newState - ? getString(R.string.switch_bar_on) - : getString(R.string.switch_bar_off)); - } - }); - } - - @Override - public void onResume() { - super.onResume(); - MetricsLogger.visibility( - getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, true); - } - - @Override - public void onPause() { - super.onPause(); - MetricsLogger.visibility( - getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, false); - } - - private boolean isEnabled() { - int setting = Settings.Secure.getInt(getContext().getContentResolver(), KEY_SHOW_PNC, 0); - return setting == 1; - } - -} diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java index 20fef927e8d1..e57c0e7f1044 100644 --- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java @@ -210,7 +210,13 @@ public class ImageWallpaper extends WallpaperService { if (DEBUG) { Log.i(TAG, "onSurfaceDestroyed"); } - mSurfaceHolder = null; + mLongExecutor.execute(this::onSurfaceDestroyedSynchronized); + } + + private void onSurfaceDestroyedSynchronized() { + synchronized (mLock) { + mSurfaceHolder = null; + } } @Override @@ -241,7 +247,7 @@ public class ImageWallpaper extends WallpaperService { private void drawFrameInternal() { if (mSurfaceHolder == null) { - Log.e(TAG, "attempt to draw a frame without a valid surface"); + Log.i(TAG, "attempt to draw a frame without a valid surface"); return; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java new file mode 100644 index 000000000000..9dd337e43b6a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 The Android Open 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.accessibility.floatingmenu; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Notification; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class MenuNotificationFactoryTest extends SysuiTestCase { + private MenuNotificationFactory mMenuNotificationFactory; + + @Before + public void setUp() { + mMenuNotificationFactory = new MenuNotificationFactory(mContext); + } + + @Test + public void createHiddenNotification_hasUndoAndDeleteAction() { + Notification notification = mMenuNotificationFactory.createHiddenNotification(); + + assertThat(notification.contentIntent.getIntent().getAction()).isEqualTo( + MenuNotificationFactory.ACTION_UNDO); + assertThat(notification.deleteIntent.getIntent().getAction()).isEqualTo( + MenuNotificationFactory.ACTION_DELETE); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java index be6f3ff8d3f9..68879a54cfe4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java @@ -21,15 +21,30 @@ import static android.view.View.VISIBLE; import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; + +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_DELETE; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_UNDO; import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex; + import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -40,6 +55,8 @@ import android.os.Build; import android.os.UserHandle; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -53,16 +70,21 @@ import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.test.filters.SmallTest; +import com.android.internal.messages.nano.SystemMessageProto; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestableContext; import com.android.systemui.util.settings.SecureSettings; +import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -98,6 +120,12 @@ public class MenuViewLayerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Spy + private SysuiTestableContext mSpyContext = getContext(); @Mock private IAccessibilityFloatingMenu mFloatingMenu; @@ -110,8 +138,12 @@ public class MenuViewLayerTest extends SysuiTestCase { @Mock private AccessibilityManager mStubAccessibilityManager; + private final NotificationManager mMockNotificationManager = mock(NotificationManager.class); + @Before public void setUp() throws Exception { + mSpyContext.addMockSystemService(Context.NOTIFICATION_SERVICE, mMockNotificationManager); + final Rect mDisplayBounds = new Rect(); mDisplayBounds.set(/* left= */ 0, /* top= */ 0, DISPLAY_WINDOW_WIDTH, DISPLAY_WINDOW_HEIGHT); @@ -119,31 +151,31 @@ public class MenuViewLayerTest extends SysuiTestCase { new WindowMetrics(mDisplayBounds, fakeDisplayInsets(), /* density = */ 0.0f)); doReturn(mWindowMetrics).when(mStubWindowManager).getCurrentWindowMetrics(); - mMenuViewLayer = new MenuViewLayer(mContext, mStubWindowManager, mStubAccessibilityManager, - mFloatingMenu, mSecureSettings); + mMenuViewLayer = new MenuViewLayer(mSpyContext, mStubWindowManager, + mStubAccessibilityManager, mFloatingMenu, mSecureSettings); mMenuView = (MenuView) mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW); mMenuAnimationController = mMenuView.getMenuAnimationController(); mLastAccessibilityButtonTargets = - Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.getStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, UserHandle.USER_CURRENT); mLastEnabledAccessibilityServices = - Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.getStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, UserHandle.USER_CURRENT); mMenuViewLayer.onAttachedToWindow(); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "", UserHandle.USER_CURRENT); } @After public void tearDown() throws Exception { - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, mLastAccessibilityButtonTargets, UserHandle.USER_CURRENT); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, mLastEnabledAccessibilityServices, UserHandle.USER_CURRENT); @@ -188,7 +220,7 @@ public class MenuViewLayerTest extends SysuiTestCase { setupEnabledAccessibilityServiceList(); mMenuViewLayer.mDismissMenuAction.run(); - final String value = Settings.Secure.getString(mContext.getContentResolver(), + final String value = Settings.Secure.getString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); assertThat(value).isEqualTo(""); @@ -203,7 +235,7 @@ public class MenuViewLayerTest extends SysuiTestCase { AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY)).thenReturn(stubShortcutTargets); mMenuViewLayer.mDismissMenuAction.run(); - final String value = Settings.Secure.getString(mContext.getContentResolver(), + final String value = Settings.Secure.getString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); assertThat(value).isEqualTo(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString()); @@ -278,9 +310,60 @@ public class MenuViewLayerTest extends SysuiTestCase { assertThat(mMenuView.getTranslationX()).isEqualTo(beforePosition.x); assertThat(mMenuView.getTranslationY()).isEqualTo(beforePosition.y); } + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void onReleasedInTarget_hideMenuAndShowNotificationWithExpectedActions() { + dragMenuThenReleasedInTarget(); + + verify(mMockNotificationManager).notify( + eq(SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN), + any(Notification.class)); + ArgumentCaptor<IntentFilter> intentFilterCaptor = ArgumentCaptor.forClass( + IntentFilter.class); + verify(mSpyContext).registerReceiver( + any(BroadcastReceiver.class), + intentFilterCaptor.capture(), + anyInt()); + assertThat(intentFilterCaptor.getValue().matchAction(ACTION_UNDO)).isTrue(); + assertThat(intentFilterCaptor.getValue().matchAction(ACTION_DELETE)).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void receiveActionUndo_dismissNotificationAndMenuVisible() { + ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass( + BroadcastReceiver.class); + dragMenuThenReleasedInTarget(); + + verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(), + any(IntentFilter.class), anyInt()); + broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_UNDO)); + + verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue()); + verify(mMockNotificationManager).cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + assertThat(mMenuView.getVisibility()).isEqualTo(VISIBLE); + } + + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void receiveActionDelete_dismissNotificationAndHideMenu() { + ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = ArgumentCaptor.forClass( + BroadcastReceiver.class); + dragMenuThenReleasedInTarget(); + + verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(), + any(IntentFilter.class), anyInt()); + broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_DELETE)); + + verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue()); + verify(mMockNotificationManager).cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + verify(mFloatingMenu).hide(); + } private void setupEnabledAccessibilityServiceList() { - Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.putString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString()); @@ -344,6 +427,12 @@ public class MenuViewLayerTest extends SysuiTestCase { springAnimation.skipToEnd(); springAnimation.doAnimationFrame(500); }); + } + private void dragMenuThenReleasedInTarget() { + MagnetizedObject.MagnetListener magnetListener = + mMenuViewLayer.getDragToInteractAnimationController().getMagnetListener(); + magnetListener.onReleasedInTarget( + new MagnetizedObject.MagneticTarget(mock(View.class), 200)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt index 9e3c576ac536..bd4973d65006 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequestTest.kt @@ -1,5 +1,7 @@ package com.android.systemui.biometrics.domain.model +import android.hardware.biometrics.PromptContentListItemBulletedText +import android.hardware.biometrics.PromptVerticalListContentView import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal @@ -23,11 +25,21 @@ class BiometricPromptRequestTest : SysuiTestCase() { val title = "what" val subtitle = "a" val description = "request" + val contentView = + PromptVerticalListContentView.Builder() + .setDescription("content description") + .addListItem(PromptContentListItemBulletedText("content text")) + .build() val fpPros = fingerprintSensorPropertiesInternal().first() val request = BiometricPromptRequest.Biometric( - promptInfo(title = title, subtitle = subtitle, description = description), + promptInfo( + title = title, + subtitle = subtitle, + description = description, + contentView = contentView + ), BiometricUserInfo(USER_ID), BiometricOperationInfo(OPERATION_ID), BiometricModalities(fingerprintProperties = fpPros), @@ -36,6 +48,7 @@ class BiometricPromptRequestTest : SysuiTestCase() { assertThat(request.title).isEqualTo(title) assertThat(request.subtitle).isEqualTo(subtitle) assertThat(request.description).isEqualTo(description) + assertThat(request.contentView).isEqualTo(contentView) assertThat(request.userInfo).isEqualTo(BiometricUserInfo(USER_ID)) assertThat(request.operationInfo).isEqualTo(BiometricOperationInfo(OPERATION_ID)) assertThat(request.modalities) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index 6170e0c2db1a..bf61c2e6d32c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -18,7 +18,10 @@ package com.android.systemui.biometrics.ui.viewmodel import android.content.res.Configuration import android.graphics.Point +import android.hardware.biometrics.PromptContentListItemBulletedText +import android.hardware.biometrics.PromptContentView import android.hardware.biometrics.PromptInfo +import android.hardware.biometrics.PromptVerticalListContentView import android.hardware.face.FaceSensorPropertiesInternal import android.hardware.fingerprint.FingerprintSensorProperties import android.hardware.fingerprint.FingerprintSensorPropertiesInternal @@ -60,7 +63,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before @@ -69,7 +71,6 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.mockito.Mock -import org.mockito.Mockito.times import org.mockito.junit.MockitoJUnit private const val USER_ID = 4 @@ -101,6 +102,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa private lateinit var selector: PromptSelectorInteractor private lateinit var viewModel: PromptViewModel private lateinit var iconViewModel: PromptIconViewModel + private lateinit var promptContentView: PromptContentView @Before fun setup() { @@ -136,6 +138,10 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa selector = PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) selector.resetPrompt() + promptContentView = + PromptVerticalListContentView.Builder() + .addListItem(PromptContentListItemBulletedText("test")) + .build() viewModel = PromptViewModel( @@ -1200,6 +1206,26 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } } + @Test + fun descriptionOverriddenByContentView() = + runGenericTest(contentView = promptContentView, description = "test description") { + val contentView by collectLastValue(viewModel.contentView) + val description by collectLastValue(viewModel.description) + + assertThat(description).isEqualTo("") + assertThat(contentView).isEqualTo(promptContentView) + } + + @Test + fun descriptionWithoutContentView() = + runGenericTest(description = "test description") { + val contentView by collectLastValue(viewModel.contentView) + val description by collectLastValue(viewModel.description) + + assertThat(description).isEqualTo("test description") + assertThat(contentView).isNull() + } + /** Asserts that the selected buttons are visible now. */ private suspend fun TestScope.assertButtonsVisible( tryAgain: Boolean = false, @@ -1219,6 +1245,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa private fun runGenericTest( doNotStart: Boolean = false, allowCredentialFallback: Boolean = false, + description: String? = null, + contentView: PromptContentView? = null, block: suspend TestScope.() -> Unit ) { selector.initializePrompt( @@ -1226,6 +1254,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa allowCredentialFallback = allowCredentialFallback, fingerprint = testCase.fingerprint, face = testCase.face, + descriptionFromApp = description, + contentViewFromApp = contentView, ) // put the view model in the initial authenticating state, unless explicitly skipped @@ -1401,11 +1431,15 @@ private fun PromptSelectorInteractor.initializePrompt( face: FaceSensorPropertiesInternal? = null, requireConfirmation: Boolean = false, allowCredentialFallback: Boolean = false, + descriptionFromApp: String? = null, + contentViewFromApp: PromptContentView? = null, ) { val info = PromptInfo().apply { title = "t" subtitle = "s" + description = descriptionFromApp + contentView = contentViewFromApp authenticators = listOf(face, fingerprint).extractAuthenticatorTypes() isDeviceCredentialAllowed = allowCredentialFallback isConfirmationRequested = requireConfirmation diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt index c4df27c2ccb2..cb8c40c333b3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.bouncer.ui.BouncerView import com.android.systemui.classifier.FalsingCollector import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository @@ -69,6 +70,7 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() { private val bouncerRepository = FakeKeyguardBouncerRepository() private val biometricSettingsRepository = FakeBiometricSettingsRepository() + private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository() private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor @@ -112,7 +114,7 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() { DeviceEntrySideFpsOverlayInteractor( testScope.backgroundScope, mContext, - FakeDeviceEntryFingerprintAuthRepository(), + deviceEntryFingerprintAuthRepository, primaryBouncerInteractor, alternateBouncerInteractor, keyguardUpdateMonitor @@ -216,6 +218,30 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() { assertThat(showIndicatorForDeviceEntry).isEqualTo(false) } + @Test + fun ignoresDuplicateRequestsToShowIndicatorForDeviceEntry() = + testScope.runTest { + val showIndicatorForDeviceEntry by collectValues(underTest.showIndicatorForDeviceEntry) + runCurrent() + + // Request to show indicator for primary bouncer showing + updatePrimaryBouncer( + isShowing = true, + isAnimatingAway = false, + fpsDetectionRunning = true, + isUnlockingWithFpAllowed = true + ) + + // Another request to show indicator for deviceEntryFingerprintAuthRepository update + deviceEntryFingerprintAuthRepository.setShouldUpdateIndicatorVisibility(true) + + // Request to show indicator for alternate bouncer showing + bouncerRepository.setAlternateVisible(true) + + // Ensure only one show request is sent + assertThat(showIndicatorForDeviceEntry).containsExactly(false, true) + } + private fun updatePrimaryBouncer( isShowing: Boolean, isAnimatingAway: Boolean, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt index 8e81185d6dcf..809947d2fec7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt @@ -63,6 +63,8 @@ class FromPrimaryBouncerTransitionInteractorTest : KeyguardTransitionInteractorT transitionRepository = super.transitionRepository, transitionInteractor = super.transitionInteractor, scope = super.testScope.backgroundScope, + bgDispatcher = super.testDispatcher, + mainDispatcher = super.testDispatcher, keyguardInteractor = super.keyguardInteractor, flags = FakeFeatureFlags(), keyguardSecurityModel = mock(), diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index b8a8bdf06954..0ea4e9f8d416 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -20,9 +20,13 @@ import android.app.StatusBarManager import androidx.test.filters.SmallTest import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN -import com.android.keyguard.TestScopeProvider +import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory +import com.android.systemui.communal.shared.model.CommunalSceneKey +import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.keyguard.data.repository.FakeCommandQueue @@ -51,6 +55,9 @@ import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runCurrent @@ -102,14 +109,18 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { FromPrimaryBouncerTransitionInteractor private lateinit var fromDreamingLockscreenHostedTransitionInteractor: FromDreamingLockscreenHostedTransitionInteractor + private lateinit var fromGlanceableHubTransitionInteractor: + FromGlanceableHubTransitionInteractor private lateinit var powerInteractor: PowerInteractor private lateinit var keyguardInteractor: KeyguardInteractor + private lateinit var communalInteractor: CommunalInteractor @Before fun setUp() { MockitoAnnotations.initMocks(this) - testScope = TestScopeProvider.getTestScope() + val testDispatcher = StandardTestDispatcher() + testScope = TestScope(testDispatcher) keyguardRepository = FakeKeyguardRepository() bouncerRepository = FakeKeyguardBouncerRepository() @@ -117,10 +128,13 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { shadeRepository = FakeShadeRepository() transitionRepository = spy(FakeKeyguardTransitionRepository()) powerInteractor = PowerInteractorFactory.create().powerInteractor + communalInteractor = + CommunalInteractorFactory.create(testScope = testScope).communalInteractor whenever(keyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(PIN) featureFlags = FakeFeatureFlags().apply { set(Flags.KEYGUARD_WM_STATE_REFACTOR, false) } + mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB) keyguardInteractor = createKeyguardInteractor() @@ -136,15 +150,25 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { ) .keyguardTransitionInteractor + val glanceableHubTransitions = + GlanceableHubTransitions( + testScope, + transitionInteractor, + transitionRepository, + communalInteractor + ) fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, flags = featureFlags, shadeRepository = shadeRepository, powerInteractor = powerInteractor, + glanceableHubTransitions = glanceableHubTransitions, inWindowLauncherUnlockAnimationInteractor = { InWindowLauncherUnlockAnimationInteractor( InWindowLauncherUnlockAnimationRepository(), @@ -160,6 +184,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -173,6 +199,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromDreamingTransitionInteractor = FromDreamingTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -182,6 +210,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromDreamingLockscreenHostedTransitionInteractor = FromDreamingLockscreenHostedTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -191,6 +221,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromAodTransitionInteractor = FromAodTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -200,6 +232,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromGoneTransitionInteractor = FromGoneTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -210,6 +244,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromDozingTransitionInteractor = FromDozingTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -220,6 +256,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromOccludedTransitionInteractor = FromOccludedTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, @@ -230,12 +268,24 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { fromAlternateBouncerTransitionInteractor = FromAlternateBouncerTransitionInteractor( scope = testScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, transitionRepository = transitionRepository, transitionInteractor = transitionInteractor, powerInteractor = powerInteractor, ) .apply { start() } + + fromGlanceableHubTransitionInteractor = + FromGlanceableHubTransitionInteractor( + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, + glanceableHubTransitions = glanceableHubTransitions, + transitionRepository = transitionRepository, + transitionInteractor = transitionInteractor, + ) + .apply { start() } } @Test @@ -1391,6 +1441,124 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { coroutineContext.cancelChildren() } + @Test + fun lockscreenToGlanceableHub() = + testScope.runTest { + // GIVEN a prior transition has run to LOCKSCREEN + runTransitionAndSetWakefulness(KeyguardState.AOD, KeyguardState.LOCKSCREEN) + runCurrent() + + // WHEN a glanceable hub transition starts + val currentScene = CommunalSceneKey.Blank + val targetScene = CommunalSceneKey.Communal + + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + communalInteractor.setTransitionState(transitionState) + progress.value = .1f + runCurrent() + + // THEN a transition from LOCKSCREEN => GLANCEABLE_HUB should occur + val info = + withArgCaptor<TransitionInfo> { + verify(transitionRepository).startTransition(capture()) + } + assertThat(info.ownerName) + .isEqualTo(FromLockscreenTransitionInteractor::class.simpleName) + assertThat(info.from).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info.to).isEqualTo(KeyguardState.GLANCEABLE_HUB) + assertThat(info.animator).isNull() // transition should be manually animated + + // WHEN the user stops dragging and the glanceable hub opening is cancelled + clearInvocations(transitionRepository) + runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB) + val idleTransitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(currentScene) + ) + communalInteractor.setTransitionState(idleTransitionState) + runCurrent() + + // THEN a transition from GLANCEABLE_HUB => LOCKSCREEN should occur + val info2 = + withArgCaptor<TransitionInfo> { + verify(transitionRepository).startTransition(capture()) + } + assertThat(info2.from).isEqualTo(KeyguardState.GLANCEABLE_HUB) + assertThat(info2.to).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info.animator).isNull() // transition should be manually animated + + coroutineContext.cancelChildren() + } + + @Test + fun glanceableHubToLockscreen() = + testScope.runTest { + // GIVEN a prior transition has run to GLANCEABLE_HUB + runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB) + runCurrent() + + // WHEN a transition away from glanceable hub starts + val currentScene = CommunalSceneKey.Communal + val targetScene = CommunalSceneKey.Blank + + val progress = MutableStateFlow(0f) + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + progress = progress, + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + communalInteractor.setTransitionState(transitionState) + progress.value = .1f + runCurrent() + + // THEN a transition from GLANCEABLE_HUB => LOCKSCREEN should occur + val info = + withArgCaptor<TransitionInfo> { + verify(transitionRepository).startTransition(capture()) + } + assertThat(info.ownerName) + .isEqualTo(FromGlanceableHubTransitionInteractor::class.simpleName) + assertThat(info.from).isEqualTo(KeyguardState.GLANCEABLE_HUB) + assertThat(info.to).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info.animator).isNull() // transition should be manually animated + + // WHEN the user stops dragging and the glanceable hub closing is cancelled + clearInvocations(transitionRepository) + runTransitionAndSetWakefulness(KeyguardState.GLANCEABLE_HUB, KeyguardState.LOCKSCREEN) + val idleTransitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Idle(currentScene) + ) + communalInteractor.setTransitionState(idleTransitionState) + runCurrent() + + // THEN a transition from LOCKSCREEN => GLANCEABLE_HUB should occur + val info2 = + withArgCaptor<TransitionInfo> { + verify(transitionRepository).startTransition(capture()) + } + assertThat(info2.from).isEqualTo(KeyguardState.LOCKSCREEN) + assertThat(info2.to).isEqualTo(KeyguardState.GLANCEABLE_HUB) + assertThat(info.animator).isNull() // transition should be manually animated + + coroutineContext.cancelChildren() + } + private fun createKeyguardInteractor(): KeyguardInteractor { return KeyguardInteractorFactory.create( featureFlags = featureFlags, diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt index edd781dec3a0..2d9d5ed2b5e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowTest.kt @@ -20,14 +20,16 @@ import androidx.test.filters.SmallTest import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.util.mockito.mock +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.time.Duration.Companion.milliseconds -import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -37,23 +39,21 @@ import org.junit.runners.JUnit4 @SmallTest @RunWith(JUnit4::class) class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { - private lateinit var underTest: KeyguardTransitionAnimationFlow.SharedFlowBuilder - private lateinit var repository: FakeKeyguardTransitionRepository - private lateinit var testScope: TestScope + val kosmos = testKosmos() + val testScope = kosmos.testScope + val animationFlow = kosmos.keyguardTransitionAnimationFlow + val repository = kosmos.fakeKeyguardTransitionRepository + + private lateinit var underTest: KeyguardTransitionAnimationFlow.FlowBuilder @Before fun setUp() { - testScope = TestScope() - repository = FakeKeyguardTransitionRepository() underTest = - KeyguardTransitionAnimationFlow( - testScope.backgroundScope, - mock(), - ) - .setup( - duration = 1000.milliseconds, - stepFlow = repository.transitions, - ) + animationFlow.setup( + duration = 1000.milliseconds, + from = KeyguardState.GONE, + to = KeyguardState.DREAMING, + ) } @Test(expected = IllegalArgumentException::class) @@ -83,6 +83,8 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { onFinish = { 10f }, ) var animationValues = collectLastValue(flow) + runCurrent() + repository.sendTransitionStep(step(1f, TransitionState.FINISHED), validateStep = false) assertThat(animationValues()).isEqualTo(10f) } @@ -97,6 +99,8 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { onCancel = { 100f }, ) var animationValues = collectLastValue(flow) + runCurrent() + repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) assertThat(animationValues()).isEqualTo(100f) } @@ -111,6 +115,8 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { onStep = { it }, ) var animationValues = collectLastValue(flow) + runCurrent() + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) assertThat(animationValues()).isEqualTo(0f) @@ -137,6 +143,8 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { onStep = { it }, ) var animationValues = collectLastValue(flow) + runCurrent() + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) assertFloat(animationValues(), EMPHASIZED_ACCELERATE.getInterpolation(0f)) repository.sendTransitionStep(step(0.5f, TransitionState.RUNNING)) @@ -157,17 +165,56 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() { duration = 1000.milliseconds, onStep = { it * 2 }, ) - var animationValues = collectLastValue(flow) + val animationValues by collectLastValue(flow) + runCurrent() + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) - assertFloat(animationValues(), 0f) + assertFloat(animationValues, 0f) repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) - assertFloat(animationValues(), 0.6f) + assertFloat(animationValues, 0.6f) repository.sendTransitionStep(step(0.6f, TransitionState.RUNNING)) - assertFloat(animationValues(), 1.2f) + assertFloat(animationValues, 1.2f) repository.sendTransitionStep(step(0.8f, TransitionState.RUNNING)) - assertFloat(animationValues(), 1.6f) + assertFloat(animationValues, 1.6f) repository.sendTransitionStep(step(1f, TransitionState.RUNNING)) - assertFloat(animationValues(), 2f) + assertFloat(animationValues, 2f) + } + + @Test + fun sameFloatValueWithTheSameTransitionStateDoesNotEmitTwice() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 1000.milliseconds, + onStep = { it }, + ) + val values by collectValues(flow) + runCurrent() + + repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) + repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) + + assertThat(values.size).isEqualTo(1) + assertThat(values[0]).isEqualTo(0.3f) + } + + @Test + fun sameFloatValueWithADifferentTransitionStateDoesEmitTwice() = + testScope.runTest { + val flow = + underTest.sharedFlow( + duration = 1000.milliseconds, + onStep = { it }, + ) + val values by collectValues(flow) + runCurrent() + + repository.sendTransitionStep(step(0.3f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING)) + + assertThat(values.size).isEqualTo(2) + assertThat(values[0]).isEqualTo(0.3f) + assertThat(values[0]).isEqualTo(0.3f) } private fun assertFloat(actual: Float?, expected: Float) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt index d959872fa80c..87391cce9136 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -50,6 +51,7 @@ class AlternateBouncerViewModelTest : SysuiTestCase() { fun transitionToAlternateBouncer_scrimAlphaUpdate() = testScope.runTest { val scrimAlphas by collectValues(underTest.scrimAlpha) + runCurrent() transitionRepository.sendTransitionSteps( listOf( @@ -69,17 +71,17 @@ class AlternateBouncerViewModelTest : SysuiTestCase() { fun transitionFromAlternateBouncer_scrimAlphaUpdate() = testScope.runTest { val scrimAlphas by collectValues(underTest.scrimAlpha) + runCurrent() transitionRepository.sendTransitionSteps( listOf( - stepToAlternateBouncer(0f, TransitionState.STARTED), - stepToAlternateBouncer(.4f), - stepToAlternateBouncer(.6f), - stepToAlternateBouncer(1f), + stepFromAlternateBouncer(0f, TransitionState.STARTED), + stepFromAlternateBouncer(.4f), + stepFromAlternateBouncer(.6f), + stepFromAlternateBouncer(1f), ), testScope, ) - assertThat(scrimAlphas.size).isEqualTo(4) scrimAlphas.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt index af8d8a8978b5..795e68ddf335 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -63,6 +64,7 @@ class AodToLockscreenTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() val deviceEntryBackgroundViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + runCurrent() // fade in repository.sendTransitionStep(step(0f, TransitionState.STARTED)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt index daafe12514ba..75994da6c934 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt @@ -39,6 +39,7 @@ import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -78,6 +79,8 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { fun scrimAlpha_runDimissFromKeyguard_shadeExpanded() = testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) + runCurrent() + shadeRepository.setLockscreenShadeExpansion(1f) whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) @@ -101,6 +104,8 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { fun scrimAlpha_runDimissFromKeyguard_shadeNotExpanded() = testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) + runCurrent() + shadeRepository.setLockscreenShadeExpansion(0f) whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true) @@ -123,6 +128,7 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { fun scrimBehindAlpha_leaveShadeOpen() = testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) + runCurrent() sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) @@ -146,6 +152,8 @@ class BouncerToGoneFlowsTest : SysuiTestCase() { fun scrimBehindAlpha_doNotLeaveShadeOpen() = testScope.runTest { val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER)) + runCurrent() + keyguardTransitionRepository.sendTransitionSteps( listOf( step(0f, TransitionState.STARTED), diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt index dd542d482745..471029b17873 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt @@ -20,18 +20,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository -import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep -import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow -import com.android.systemui.util.mockito.mock +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -39,29 +36,10 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class DozingToLockscreenTransitionViewModelTest : SysuiTestCase() { - private lateinit var testScope: TestScope - private lateinit var underTest: DozingToLockscreenTransitionViewModel - private lateinit var repository: FakeKeyguardTransitionRepository - - @Before - fun setUp() { - testScope = TestScope() - repository = FakeKeyguardTransitionRepository() - underTest = - DozingToLockscreenTransitionViewModel( - interactor = - KeyguardTransitionInteractorFactory.create( - scope = testScope.backgroundScope, - repository = repository, - ) - .keyguardTransitionInteractor, - animationFlow = - KeyguardTransitionAnimationFlow( - scope = testScope.backgroundScope, - logger = mock() - ), - ) - } + val kosmos = testKosmos() + val testScope = kosmos.testScope + val repository = kosmos.fakeKeyguardTransitionRepository + val underTest = kosmos.dozingToLockscreenTransitionViewModel @Test fun deviceEntryParentViewShows() = diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt index a105008f3f37..1c9c942eafc6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -52,6 +53,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { val pixels = -100f val enterFromTopTranslationY by collectLastValue(underTest.enterFromTopTranslationY(pixels.toInt())) + runCurrent() // The animation should only start > .4f way through repository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -72,6 +74,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { fun enterFromTopAnimationAlpha() = testScope.runTest { val enterFromTopAnimationAlpha by collectLastValue(underTest.enterFromTopAnimationAlpha) + runCurrent() // The animation should only start > .4f way through repository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -92,6 +95,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val deviceEntryBackgroundViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + runCurrent() // immediately 0f repository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -113,6 +117,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // animation doesn't start until the end repository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -137,6 +142,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsRearFps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // animation doesn't start until the end repository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -161,6 +167,7 @@ class GoneToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // animation doesn't start until the end repository.sendTransitionStep(step(0f, TransitionState.STARTED)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt index 5e6231734d32..1912987cc447 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -51,6 +52,7 @@ class OccludedToAodTransitionViewModelTest : SysuiTestCase() { testScope.runTest { val deviceEntryBackgroundViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + runCurrent() // immediately 0f keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -72,6 +74,7 @@ class OccludedToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // immediately 1f keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -96,6 +99,7 @@ class OccludedToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsRearFps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // no updates keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -120,6 +124,7 @@ class OccludedToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // no updates keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt index 9729022ca890..c55c27c3b516 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -54,6 +55,7 @@ class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() val deviceEntryBackgroundViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + runCurrent() // immediately 0f keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -75,6 +77,7 @@ class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -92,6 +95,7 @@ class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsRearFps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() // animation doesn't start until the end keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) @@ -116,6 +120,7 @@ class PrimaryBouncerToAodTransitionViewModelTest : SysuiTestCase() { fingerprintPropertyRepository.supportsUdfps() biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha) + runCurrent() keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) assertThat(deviceEntryParentViewAlpha).isNull() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt index 2c6436e07b91..0796af065790 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt @@ -30,6 +30,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -71,6 +72,7 @@ class PrimaryBouncerToLockscreenTransitionViewModelTest : SysuiTestCase() { testScope.runTest { fingerprintPropertyRepository.supportsUdfps() val bgViewAlpha by collectLastValue(underTest.deviceEntryBackgroundViewAlpha) + runCurrent() // immediately 1f keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index 2f35380e562b..59965022d7cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -64,8 +64,6 @@ import com.android.systemui.ActivityIntentHelper import com.android.systemui.SysuiTestCase import com.android.systemui.bluetooth.BroadcastDialogController import com.android.systemui.broadcast.BroadcastSender -import com.android.systemui.flags.FakeFeatureFlags -import com.android.systemui.flags.Flags import com.android.systemui.media.controls.MediaTestUtils import com.android.systemui.media.controls.models.GutsViewHolder import com.android.systemui.media.controls.models.player.MediaAction @@ -227,11 +225,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var recProgressBar2: SeekBar @Mock private lateinit var recProgressBar3: SeekBar private var shouldShowBroadcastButton: Boolean = false - private val fakeFeatureFlag = - FakeFeatureFlags().apply { - this.set(Flags.UMO_SURFACE_RIPPLE, false) - this.set(Flags.UMO_TURBULENCE_NOISE, false) - } @Mock private lateinit var globalSettings: GlobalSettings @Mock private lateinit var mediaFlags: MediaFlags @@ -275,7 +268,6 @@ public class MediaControlPanelTest : SysuiTestCase() { activityIntentHelper, lockscreenUserManager, broadcastDialogController, - fakeFeatureFlag, globalSettings, mediaFlags, ) { @@ -2397,8 +2389,7 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test - fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() { - fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true) + fun onButtonClick_playsTouchRipple() { val semanticActions = MediaButton( playOrPause = @@ -2419,31 +2410,7 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test - fun onButtonClick_touchRippleFlagDisabled_doesNotPlayTouchRipple() { - fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, false) - val semanticActions = - MediaButton( - playOrPause = - MediaAction( - icon = null, - action = {}, - contentDescription = "play", - background = null - ) - ) - val data = mediaData.copy(semanticActions = semanticActions) - player.attachPlayer(viewHolder) - player.bindPlayer(data, KEY) - - viewHolder.actionPlayPause.callOnClick() - - assertThat(viewHolder.multiRippleView.ripples.size).isEqualTo(0) - } - - @Test fun playTurbulenceNoise_finishesAfterDuration() { - fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true) - val semanticActions = MediaButton( playOrPause = @@ -2474,8 +2441,6 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun playTurbulenceNoise_whenPlaybackStateIsNotPlaying_doesNotPlayTurbulence() { - fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true) - val semanticActions = MediaButton( custom0 = diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index 5569ca9520e9..b7a9ea751438 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.shade +import android.os.PowerManager import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.testing.ViewUtils @@ -43,6 +44,8 @@ import org.junit.BeforeClass import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -52,6 +55,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { @Mock private lateinit var communalViewModel: CommunalViewModel @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var shadeInteractor: ShadeInteractor + @Mock private lateinit var powerManager: PowerManager private lateinit var containerView: View private lateinit var testableLooper: TestableLooper @@ -76,7 +80,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { communalInteractor, communalViewModel, keyguardTransitionInteractor, - shadeInteractor + shadeInteractor, + powerManager ) testableLooper = TestableLooper.get(this) @@ -90,14 +95,14 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } @Test - fun isEnabled_interactorEnabled_returnsTrue() { + fun isEnabled_interactorEnabled_interceptsTouches() { communalRepository.setIsCommunalEnabled(true) assertThat(underTest.isEnabled()).isTrue() } @Test - fun isEnabled_interactorDisabled_returnsFalse() { + fun isEnabled_interactorDisabled_doesNotIntercept() { communalRepository.setIsCommunalEnabled(false) assertThat(underTest.isEnabled()).isFalse() @@ -120,7 +125,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } @Test - fun onTouchEvent_touchInsideGestureRegion_returnsTrue() { + fun onTouchEvent_touchInsideGestureRegion_interceptsTouches() { // Communal is open. communalRepository.setDesiredScene(CommunalSceneKey.Communal) @@ -131,7 +136,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } @Test - fun onTouchEvent_subsequentTouchesAfterGestureStart_returnsTrue() { + fun onTouchEvent_subsequentTouchesAfterGestureStart_interceptsTouches() { // Communal is open. communalRepository.setDesiredScene(CommunalSceneKey.Communal) @@ -146,7 +151,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { } @Test - fun onTouchEvent_communalOpen_returnsTrue() { + fun onTouchEvent_communalOpen_interceptsTouches() { // Communal is open. communalRepository.setDesiredScene(CommunalSceneKey.Communal) @@ -155,10 +160,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { // Touch events are intercepted. assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue() + // User activity sent to PowerManager. + verify(powerManager).userActivity(any(), any(), any()) } @Test - fun onTouchEvent_communalAndBouncerShowing_returnsFalse() { + fun onTouchEvent_communalAndBouncerShowing_doesNotIntercept() { // Communal is open. communalRepository.setDesiredScene(CommunalSceneKey.Communal) @@ -170,10 +177,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { // Touch events are not intercepted. assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse() + // User activity is not sent to PowerManager. + verify(powerManager, times(0)).userActivity(any(), any(), any()) } @Test - fun onTouchEvent_communalAndShadeShowing_returnsFalse() { + fun onTouchEvent_communalAndShadeShowing_doesNotIntercept() { // Communal is open. communalRepository.setDesiredScene(CommunalSceneKey.Communal) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index a20658197a8d..49579f6f46b4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -181,7 +181,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; import com.android.systemui.statusbar.phone.TapAgainViewController; import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController; -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; @@ -191,6 +190,7 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository; +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository; import com.android.systemui.statusbar.window.StatusBarWindowStateController; import com.android.systemui.unfold.SysUIUnfoldComponent; import com.android.systemui.user.domain.interactor.UserSwitcherInteractor; @@ -346,6 +346,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { @Mock protected ActiveNotificationsInteractor mActiveNotificationsInteractor; @Mock private KeyguardClockPositionAlgorithm mKeyguardClockPositionAlgorithm; @Mock private NaturalScrollingSettingObserver mNaturalScrollingSettingObserver; + @Mock private LargeScreenHeaderHelper mLargeScreenHeaderHelper; protected final int mMaxUdfpsBurnInOffsetY = 5; protected FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic(); @@ -426,7 +427,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mContext, new ResourcesSplitShadeStateController(), mKeyguardInteractor, - deviceEntryUdfpsInteractor + deviceEntryUdfpsInteractor, + () -> mLargeScreenHeaderHelper ), mShadeRepository ) @@ -812,7 +814,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mActiveNotificationsInteractor, mJavaAdapter, mCastController, - new ResourcesSplitShadeStateController() + new ResourcesSplitShadeStateController(), + () -> mLargeScreenHeaderHelper ); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java index 9d8b21464585..791c080e9219 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java @@ -23,8 +23,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; import static com.google.common.truth.Truth.assertThat; -import static kotlinx.coroutines.flow.FlowKt.emptyFlow; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -38,6 +36,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static kotlinx.coroutines.flow.FlowKt.emptyFlow; + import android.app.IActivityManager; import android.content.pm.ActivityInfo; import android.content.res.Configuration; @@ -56,6 +56,8 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlagsClassic; @@ -67,6 +69,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepos import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository; import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.GlanceableHubTransitions; import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -94,11 +97,11 @@ import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ScrimController; -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository; +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.user.domain.interactor.UserSwitcherInteractor; @@ -143,6 +146,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Mock private SelectedUserInteractor mSelectedUserInteractor; @Mock private UserTracker mUserTracker; @Mock private SceneContainerFlags mSceneContainerFlags; + @Mock private LargeScreenHeaderHelper mLargeScreenHeaderHelper; @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters; @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener; @@ -199,6 +203,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { new ConfigurationInteractor(configurationRepository), shadeRepository, () -> sceneInteractor); + CommunalInteractor communalInteractor = + CommunalInteractorFactory.create().getCommunalInteractor(); FakeKeyguardTransitionRepository keyguardTransitionRepository = new FakeKeyguardTransitionRepository(); @@ -215,10 +221,18 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, shadeRepository, powerInteractor, + new GlanceableHubTransitions( + mTestScope, + keyguardTransitionInteractor, + keyguardTransitionRepository, + communalInteractor + ), () -> new InWindowLauncherUnlockAnimationInteractor( new InWindowLauncherUnlockAnimationRepository(), @@ -233,6 +247,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, mKeyguardSecurityModel, @@ -261,7 +277,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { mContext, new ResourcesSplitShadeStateController(), keyguardInteractor, - deviceEntryUdfpsInteractor), + deviceEntryUdfpsInteractor, + () -> mLargeScreenHeaderHelper), shadeRepository ) ); @@ -519,8 +536,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Test public void udfpsEnrolled_minAndMaxRefreshRateSetToPreferredRefreshRate() { - // GIVEN udfps is enrolled - when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true); + // GIVEN optical udfps is enrolled + when(mAuthController.isOpticalUdfpsEnrolled(anyInt())).thenReturn(true); // WHEN keyguard is showing setKeyguardShowing(); @@ -534,9 +551,9 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { } @Test - public void udfpsNotEnrolled_refreshRateUnset() { + public void opticalUdfpsNotEnrolled_refreshRateUnset() { // GIVEN udfps is NOT enrolled - when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false); + when(mAuthController.isOpticalUdfpsEnrolled(anyInt())).thenReturn(false); // WHEN keyguard is showing setKeyguardShowing(); @@ -551,8 +568,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase { @Test public void keyguardNotShowing_refreshRateUnset() { - // GIVEN UDFPS is enrolled - when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true); + // GIVEN optical UDFPS is enrolled + when(mAuthController.isOpticalUdfpsEnrolled(anyInt())).thenReturn(true); // WHEN keyguard is NOT showing mNotificationShadeWindowController.setKeyguardShowing(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt index ee7c6c89e4a3..a11839c56b0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.shade import android.content.Context -import android.os.Handler import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.KeyEvent @@ -25,50 +24,29 @@ import android.view.MotionEvent import android.view.View import android.view.ViewGroup import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardMessageAreaController import com.android.keyguard.KeyguardSecurityContainerController -import com.android.keyguard.KeyguardSecurityModel -import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.systemui.Flags import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository -import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl -import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor -import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor -import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil -import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor -import com.android.systemui.bouncer.ui.BouncerView -import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel -import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.bouncer.ui.binder.BouncerViewBinder import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.compose.ComposeFacade.isComposeAvailable import com.android.systemui.dock.DockManager import com.android.systemui.dump.DumpManager -import com.android.systemui.log.logcatLogBuffer import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED import com.android.systemui.flags.Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION import com.android.systemui.flags.Flags.TRACKPAD_GESTURE_COMMON import com.android.systemui.flags.Flags.TRACKPAD_GESTURE_FEATURES -import com.android.systemui.flags.SystemPropertiesHelper import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler -import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardUnlockAnimationController -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeTrustRepository -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies -import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel -import com.android.systemui.log.BouncerLogger import com.android.systemui.res.R import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.DragDownHelper @@ -86,16 +64,15 @@ import com.android.systemui.statusbar.phone.DozeScrimController import com.android.systemui.statusbar.phone.DozeServiceHost import com.android.systemui.statusbar.phone.PhoneStatusBarViewController import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager -import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.unfold.UnfoldTransitionProgressProvider -import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat +import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.test.TestScope @@ -110,9 +87,8 @@ import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.times import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations -import java.util.Optional import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -133,7 +109,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock private lateinit var shadeLogger: ShadeLogger @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var ambientState: AmbientState - @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel @Mock private lateinit var stackScrollLayoutController: NotificationStackScrollLayoutController @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager @Mock private lateinit var statusBarWindowStateController: StatusBarWindowStateController @@ -156,8 +131,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { @Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock lateinit var dragDownHelper: DragDownHelper @Mock lateinit var mSelectedUserInteractor: SelectedUserInteractor - @Mock - lateinit var primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel @Mock lateinit var sysUIKeyEventHandler: SysUIKeyEventHandler @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor @@ -224,55 +197,18 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() { dumpManager, pulsingGestureListener, mLockscreenHostedDreamGestureListener, - keyguardBouncerViewModel, - keyguardBouncerComponentFactory, - mock(KeyguardMessageAreaController.Factory::class.java), keyguardTransitionInteractor, - primaryBouncerToGoneTransitionViewModel, mGlanceableHubContainerController, notificationLaunchAnimationInteractor, featureFlagsClassic, fakeClock, - BouncerMessageInteractor( - repository = BouncerMessageRepositoryImpl(), - userRepository = FakeUserRepository(), - countDownTimerUtil = mock(CountDownTimerUtil::class.java), - updateMonitor = mock(KeyguardUpdateMonitor::class.java), - biometricSettingsRepository = FakeBiometricSettingsRepository(), - applicationScope = testScope.backgroundScope, - trustRepository = FakeTrustRepository(), - systemPropertiesHelper = mock(SystemPropertiesHelper::class.java), - primaryBouncerInteractor = - PrimaryBouncerInteractor( - FakeKeyguardBouncerRepository(), - mock(BouncerView::class.java), - mock(Handler::class.java), - mock(KeyguardStateController::class.java), - mock(KeyguardSecurityModel::class.java), - mock(PrimaryBouncerCallbackInteractor::class.java), - mock(FalsingCollector::class.java), - mock(DismissCallbackRegistry::class.java), - context, - mock(KeyguardUpdateMonitor::class.java), - FakeTrustRepository(), - testScope.backgroundScope, - mSelectedUserInteractor, - mock(DeviceEntryFaceAuthInteractor::class.java) - ), - facePropertyRepository = FakeFacePropertyRepository(), - deviceEntryFingerprintAuthRepository = - FakeDeviceEntryFingerprintAuthRepository(), - faceAuthRepository = FakeDeviceEntryFaceAuthRepository(), - securityModel = mock(KeyguardSecurityModel::class.java), - ), - BouncerLogger(logcatLogBuffer("BouncerLog")), sysUIKeyEventHandler, quickSettingsController, primaryBouncerInteractor, alternateBouncerInteractor, - mSelectedUserInteractor, - { mock (JavaAdapter::class.java )}, + { mock(JavaAdapter::class.java) }, { mock(AlternateBouncerDependencies::class.java) }, + mock(BouncerViewBinder::class.java) ) underTest.setupExpandedStatusBar() underTest.setDragDownHelper(dragDownHelper) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt index 33d60ea9f45c..0c4bf8120d25 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt @@ -15,51 +15,28 @@ */ package com.android.systemui.shade -import android.os.Handler import android.os.SystemClock import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.MotionEvent import android.widget.FrameLayout import androidx.test.filters.SmallTest -import com.android.keyguard.KeyguardMessageAreaController import com.android.keyguard.KeyguardSecurityContainerController -import com.android.keyguard.KeyguardSecurityModel -import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.LockIconViewController import com.android.keyguard.dagger.KeyguardBouncerComponent import com.android.systemui.Flags as AConfigFlags import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.FakeFacePropertyRepository -import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl -import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor -import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor -import com.android.systemui.bouncer.domain.interactor.CountDownTimerUtil -import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor -import com.android.systemui.bouncer.ui.BouncerView -import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel -import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.dock.DockManager import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags -import com.android.systemui.flags.SystemPropertiesHelper import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler -import com.android.systemui.keyguard.DismissCallbackRegistry import com.android.systemui.keyguard.KeyguardUnlockAnimationController -import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository -import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.FakeTrustRepository import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies -import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel -import com.android.systemui.log.BouncerLogger -import com.android.systemui.log.logcatLogBuffer -import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler import com.android.systemui.statusbar.DragDownHelper @@ -77,11 +54,8 @@ import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.DozeScrimController import com.android.systemui.statusbar.phone.DozeServiceHost import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager -import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.statusbar.window.StatusBarWindowStateController import com.android.systemui.unfold.UnfoldTransitionProgressProvider -import com.android.systemui.user.data.repository.FakeUserRepository -import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.JavaAdapter import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock @@ -137,7 +111,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { @Mock private lateinit var pulsingGestureListener: PulsingGestureListener @Mock private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener - @Mock private lateinit var keyguardBouncerViewModel: KeyguardBouncerViewModel @Mock private lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory @Mock private lateinit var keyguardBouncerComponent: KeyguardBouncerComponent @Mock @@ -150,10 +123,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor @Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor - @Mock private lateinit var mSelectedUserInteractor: SelectedUserInteractor - @Mock - private lateinit var primaryBouncerToGoneTransitionViewModel: - PrimaryBouncerToGoneTransitionViewModel @Captor private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler> @@ -217,55 +186,18 @@ class NotificationShadeWindowViewTest : SysuiTestCase() { dumpManager, pulsingGestureListener, mLockscreenHostedDreamGestureListener, - keyguardBouncerViewModel, - keyguardBouncerComponentFactory, - Mockito.mock(KeyguardMessageAreaController.Factory::class.java), keyguardTransitionInteractor, - primaryBouncerToGoneTransitionViewModel, mGlanceableHubContainerController, NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository()), featureFlags, FakeSystemClock(), - BouncerMessageInteractor( - repository = BouncerMessageRepositoryImpl(), - userRepository = FakeUserRepository(), - countDownTimerUtil = Mockito.mock(CountDownTimerUtil::class.java), - updateMonitor = Mockito.mock(KeyguardUpdateMonitor::class.java), - biometricSettingsRepository = FakeBiometricSettingsRepository(), - applicationScope = testScope.backgroundScope, - trustRepository = FakeTrustRepository(), - systemPropertiesHelper = Mockito.mock(SystemPropertiesHelper::class.java), - primaryBouncerInteractor = - PrimaryBouncerInteractor( - FakeKeyguardBouncerRepository(), - Mockito.mock(BouncerView::class.java), - Mockito.mock(Handler::class.java), - Mockito.mock(KeyguardStateController::class.java), - Mockito.mock(KeyguardSecurityModel::class.java), - Mockito.mock(PrimaryBouncerCallbackInteractor::class.java), - Mockito.mock(FalsingCollector::class.java), - Mockito.mock(DismissCallbackRegistry::class.java), - context, - Mockito.mock(KeyguardUpdateMonitor::class.java), - FakeTrustRepository(), - testScope.backgroundScope, - mSelectedUserInteractor, - mock(), - ), - facePropertyRepository = FakeFacePropertyRepository(), - deviceEntryFingerprintAuthRepository = - FakeDeviceEntryFingerprintAuthRepository(), - faceAuthRepository = FakeDeviceEntryFaceAuthRepository(), - securityModel = Mockito.mock(KeyguardSecurityModel::class.java), - ), - BouncerLogger(logcatLogBuffer("BouncerLog")), Mockito.mock(SysUIKeyEventHandler::class.java), quickSettingsController, primaryBouncerInteractor, alternateBouncerInteractor, - mSelectedUserInteractor, { Mockito.mock(JavaAdapter::class.java) }, { Mockito.mock(AlternateBouncerDependencies::class.java) }, + mock() ) controller.setupExpandedStatusBar() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt index 88a47eb81bde..ea3caa380cf2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerLegacyTest.kt @@ -42,6 +42,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -52,7 +53,6 @@ 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 import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.any @@ -74,15 +74,16 @@ import org.mockito.MockitoAnnotations @SmallTest class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { - @Mock lateinit var view: NotificationsQuickSettingsContainer - @Mock lateinit var navigationModeController: NavigationModeController - @Mock lateinit var overviewProxyService: OverviewProxyService - @Mock lateinit var shadeHeaderController: ShadeHeaderController - @Mock lateinit var shadeInteractor: ShadeInteractor - @Mock lateinit var fragmentService: FragmentService - @Mock lateinit var fragmentHostManager: FragmentHostManager - @Mock - lateinit var notificationStackScrollLayoutController: NotificationStackScrollLayoutController + private val view = mock<NotificationsQuickSettingsContainer>() + private val navigationModeController = mock<NavigationModeController>() + private val overviewProxyService = mock<OverviewProxyService>() + private val shadeHeaderController = mock<ShadeHeaderController>() + private val shadeInteractor = mock<ShadeInteractor>() + private val fragmentService = mock<FragmentService>() + private val fragmentHostManager = mock<FragmentHostManager>() + private val notificationStackScrollLayoutController = + mock<NotificationStackScrollLayoutController>() + private val largeScreenHeaderHelper = mock<LargeScreenHeaderHelper>() @Captor lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener> @Captor lateinit var taskbarVisibilityCaptor: ArgumentCaptor<OverviewProxyListener> @@ -123,7 +124,8 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { delayableExecutor, featureFlags, notificationStackScrollLayoutController, - ResourcesSplitShadeStateController() + ResourcesSplitShadeStateController(), + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ) overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN) @@ -480,7 +482,8 @@ class NotificationsQSContainerControllerLegacyTest : SysuiTestCase() { delayableExecutor, featureFlags, notificationStackScrollLayoutController, - ResourcesSplitShadeStateController() + ResourcesSplitShadeStateController(), + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ) controller.updateConstraints() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt index 1f37ca09dc26..c1bc303f26ea 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationsQSContainerControllerTest.kt @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.capture +import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -53,7 +54,6 @@ 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 import org.mockito.Mockito.RETURNS_DEEP_STUBS import org.mockito.Mockito.any @@ -71,15 +71,16 @@ import org.mockito.MockitoAnnotations @SmallTest class NotificationsQSContainerControllerTest : SysuiTestCase() { - @Mock lateinit var view: NotificationsQuickSettingsContainer - @Mock lateinit var navigationModeController: NavigationModeController - @Mock lateinit var overviewProxyService: OverviewProxyService - @Mock lateinit var shadeHeaderController: ShadeHeaderController - @Mock lateinit var shadeInteractor: ShadeInteractor - @Mock lateinit var fragmentService: FragmentService - @Mock lateinit var fragmentHostManager: FragmentHostManager - @Mock - lateinit var notificationStackScrollLayoutController: NotificationStackScrollLayoutController + private val view = mock<NotificationsQuickSettingsContainer>() + private val navigationModeController = mock<NavigationModeController>() + private val overviewProxyService = mock<OverviewProxyService>() + private val shadeHeaderController = mock<ShadeHeaderController>() + private val shadeInteractor = mock<ShadeInteractor>() + private val fragmentService = mock<FragmentService>() + private val fragmentHostManager = mock<FragmentHostManager>() + private val notificationStackScrollLayoutController = + mock<NotificationStackScrollLayoutController>() + private val largeScreenHeaderHelper = mock<LargeScreenHeaderHelper>() @Captor lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener> @Captor lateinit var taskbarVisibilityCaptor: ArgumentCaptor<OverviewProxyListener> @@ -122,7 +123,8 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { delayableExecutor, featureFlags, notificationStackScrollLayoutController, - ResourcesSplitShadeStateController() + ResourcesSplitShadeStateController(), + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ) overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN) @@ -463,7 +465,8 @@ class NotificationsQSContainerControllerTest : SysuiTestCase() { delayableExecutor, featureFlags, notificationStackScrollLayoutController, - ResourcesSplitShadeStateController() + ResourcesSplitShadeStateController(), + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ) controller.updateConstraints() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java index 727a6c3d1adc..a369f8280190 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java @@ -42,6 +42,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor; import com.android.systemui.dump.DumpManager; @@ -55,6 +57,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepos import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository; import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.GlanceableHubTransitions; import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -100,11 +103,11 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager; -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository; +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.user.domain.interactor.UserSwitcherInteractor; import com.android.systemui.util.kotlin.JavaAdapter; @@ -176,6 +179,7 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { @Mock protected CastController mCastController; @Mock protected UserSwitcherInteractor mUserSwitcherInteractor; @Mock protected SelectedUserInteractor mSelectedUserInteractor; + @Mock protected LargeScreenHeaderHelper mLargeScreenHeaderHelper; protected FakeDisableFlagsRepository mDisableFlagsRepository = new FakeDisableFlagsRepository(); @@ -234,6 +238,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { new ConfigurationInteractor(configurationRepository), mShadeRepository, () -> sceneInteractor); + CommunalInteractor communalInteractor = + CommunalInteractorFactory.create().getCommunalInteractor(); FakeKeyguardTransitionRepository keyguardTransitionRepository = new FakeKeyguardTransitionRepository(); @@ -250,10 +256,18 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, mShadeRepository, powerInteractor, + new GlanceableHubTransitions( + mTestScope, + keyguardTransitionInteractor, + keyguardTransitionRepository, + communalInteractor + ), () -> new InWindowLauncherUnlockAnimationInteractor( new InWindowLauncherUnlockAnimationRepository(), @@ -268,6 +282,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, mock(KeyguardSecurityModel.class), @@ -299,7 +315,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { mContext, splitShadeStateController, keyguardInteractor, - deviceEntryUdfpsInteractor), + deviceEntryUdfpsInteractor, + () -> mLargeScreenHeaderHelper), mShadeRepository ) ); @@ -384,7 +401,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase { mActiveNotificationsInteractor, new JavaAdapter(mTestScope.getBackgroundScope()), mCastController, - splitShadeStateController + splitShadeStateController, + () -> mLargeScreenHeaderHelper ); mQsController.init(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt index 65e0fa146fe3..71a7420636cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt @@ -50,8 +50,8 @@ import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.user.data.model.UserSwitcherSettingsModel import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.domain.UserDomainLayerModule @@ -163,7 +163,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { testComponent.runTest { deviceProvisioningRepository.setDeviceProvisioned(true) - userSetupRepository.setUserSetup(false) + userSetupRepository.setUserSetUp(false) userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true)) val actual by collectLastValue(underTest.isExpandToQsEnabled) @@ -175,7 +175,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { fun isExpandToQsEnabled_shadeNotEnabled_false() = testComponent.runTest { deviceProvisioningRepository.setDeviceProvisioned(true) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) disableFlagsRepository.disableFlags.value = DisableFlagsModel( @@ -191,7 +191,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { fun isExpandToQsEnabled_quickSettingsNotEnabled_false() = testComponent.runTest { deviceProvisioningRepository.setDeviceProvisioned(true) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) disableFlagsRepository.disableFlags.value = DisableFlagsModel( @@ -206,7 +206,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { fun isExpandToQsEnabled_dozing_false() = testComponent.runTest { deviceProvisioningRepository.setDeviceProvisioned(true) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) disableFlagsRepository.disableFlags.value = DisableFlagsModel( disable2 = DISABLE2_NONE, @@ -229,7 +229,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { disable2 = DISABLE2_NONE, ) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) val actual by collectLastValue(underTest.isExpandToQsEnabled) @@ -262,7 +262,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { DisableFlagsModel( disable2 = DISABLE2_NONE, ) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) val actual by collectLastValue(underTest.isExpandToQsEnabled) @@ -290,7 +290,7 @@ class ShadeInteractorImplTest : SysuiTestCase() { DisableFlagsModel( disable2 = DISABLE2_NONE, ) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) val actual by collectLastValue(underTest.isExpandToQsEnabled) @@ -322,21 +322,21 @@ class ShadeInteractorImplTest : SysuiTestCase() { DisableFlagsModel( disable2 = DISABLE2_NONE, ) - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) val actual by collectLastValue(underTest.isExpandToQsEnabled) assertThat(actual).isTrue() // WHEN the user is no longer setup - userSetupRepository.setUserSetup(false) + userSetupRepository.setUserSetUp(false) userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true)) // THEN expand is disabled assertThat(actual).isFalse() // WHEN the user is setup again - userSetupRepository.setUserSetup(true) + userSetupRepository.setUserSetUp(true) // THEN expand is enabled assertThat(actual).isTrue() diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt index ee27c5c9ba0d..64fd80d72d3f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt @@ -35,6 +35,7 @@ import com.android.systemui.plugins.PluginListener import com.android.systemui.plugins.PluginManager import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.eq +import java.util.function.BiConsumer import junit.framework.Assert.assertEquals import junit.framework.Assert.fail import kotlinx.coroutines.CoroutineDispatcher @@ -100,10 +101,7 @@ class ClockRegistryTest : SysuiTestCase() { override fun toString() = "Manager[$tag]" override fun getPackage(): String = mComponentName.getPackageName() override fun getComponentName(): ComponentName = mComponentName - - private var isDebug: Boolean = false - override fun getIsDebug(): Boolean = isDebug - override fun setIsDebug(value: Boolean) { isDebug = value } + override fun setLogFunc(func: BiConsumer<String, String>) { } override fun loadPlugin() { if (!mIsLoaded) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java index bc50c25a77a0..3defee9e6eb5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java @@ -112,7 +112,7 @@ public class PluginInstanceTest extends SysuiTestCase { mPluginInstance = mPluginInstanceFactory.create( mContext, mAppInfo, TEST_PLUGIN_COMPONENT_NAME, TestPlugin.class, mPluginListener); - mPluginInstance.setIsDebug(true); + mPluginInstance.setLogFunc((tag, msg) -> Log.d((String) tag, (String) msg)); mPluginContext = new WeakReference<>(mPluginInstance.getPluginContext()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt index f25ce0aa5278..4a365b9ab084 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt @@ -27,7 +27,8 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor import com.android.systemui.classifier.FalsingCollectorFake import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.FakeCommandQueue import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository @@ -36,6 +37,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepos import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.GlanceableHubTransitions import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -44,15 +46,16 @@ import com.android.systemui.power.data.repository.FakePowerRepository import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.scene.SceneTestUtils import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags +import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.data.repository.FakeShadeRepository import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.util.mockito.mock import kotlinx.coroutines.flow.emptyFlow import org.junit.Assert.assertEquals @@ -65,12 +68,11 @@ import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyFloat import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.eq -import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.mock import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever @SmallTest @RunWith(AndroidTestingRunner::class) @@ -79,13 +81,15 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { private val utils = SceneTestUtils(this) private val testScope = utils.testScope + private val testDispatcher = utils.testDispatcher private lateinit var shadeInteractor: ShadeInteractor private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor private lateinit var fromPrimaryBouncerTransitionInteractor: FromPrimaryBouncerTransitionInteractor - @Mock lateinit var interactionJankMonitor: InteractionJankMonitor - @Mock lateinit var mockDarkAnimator: ObjectAnimator - @Mock lateinit var deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor + private val interactionJankMonitor = mock<InteractionJankMonitor>() + private val mockDarkAnimator = mock<ObjectAnimator>() + private val deviceEntryUdfpsInteractor = mock<DeviceEntryUdfpsInteractor>() + private val largeScreenHeaderHelper = mock<LargeScreenHeaderHelper>() private lateinit var controller: StatusBarStateControllerImpl private lateinit var uiEventLogger: UiEventLoggerFake @@ -137,15 +141,24 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { { fromLockscreenTransitionInteractor }, { fromPrimaryBouncerTransitionInteractor } ) + val communalInteractor = CommunalInteractorFactory.create().communalInteractor fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor( keyguardTransitionRepository, keyguardTransitionInteractor, testScope.backgroundScope, + testDispatcher, + testDispatcher, keyguardInteractor, featureFlags, shadeRepository, powerInteractor, + GlanceableHubTransitions( + testScope, + keyguardTransitionInteractor, + keyguardTransitionRepository, + communalInteractor + ), { InWindowLauncherUnlockAnimationInteractor( InWindowLauncherUnlockAnimationRepository(), @@ -161,6 +174,8 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { keyguardTransitionRepository, keyguardTransitionInteractor, testScope.backgroundScope, + testDispatcher, + testDispatcher, keyguardInteractor, featureFlags, mock(), @@ -189,6 +204,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() { ResourcesSplitShadeStateController(), keyguardInteractor, deviceEntryUdfpsInteractor, + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ), shadeRepository, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt index 5549feefe090..91e46668ed44 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.kt @@ -37,6 +37,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.statusbar.notification.FeedbackIcon import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import junit.framework.Assert.assertEquals @@ -49,6 +50,8 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.doReturn import org.mockito.Mockito.never import org.mockito.Mockito.spy @@ -74,7 +77,8 @@ class NotificationContentViewTest : SysuiTestCase() { @Before fun setup() { initMocks(this) - fakeParent = FrameLayout(mContext, /* attrs= */ null).also { it.visibility = View.GONE } + fakeParent = + spy(FrameLayout(mContext, /* attrs= */ null).also { it.visibility = View.GONE }) row = spy( ExpandableNotificationRow(mContext, /* attrs= */ null).apply { @@ -558,6 +562,35 @@ class NotificationContentViewTest : SysuiTestCase() { verify(view.headsUpWrapper, never()).setAnimationsRunning(false) } + @Test + fun notifySubtreeAccessibilityStateChanged_notifiesParent() { + // Given: a contentView is created + val view = createContentView() + clearInvocations(fakeParent) + + // When: the contentView is notified for an A11y change + view.notifySubtreeAccessibilityStateChanged(view.contractedChild, view.contractedChild, 0) + + // Then: the contentView propagates the event to its parent + verify(fakeParent).notifySubtreeAccessibilityStateChanged(any(), any(), anyInt()) + } + + @Test + fun notifySubtreeAccessibilityStateChanged_animatingContentView_dontNotifyParent() { + // Given: a collapsed contentView is created + val view = createContentView() + clearInvocations(fakeParent) + + // And: it is animating to expanded + view.setAnimationStartVisibleType(NotificationContentView.VISIBLE_TYPE_EXPANDED) + + // When: the contentView is notified for an A11y change + view.notifySubtreeAccessibilityStateChanged(view.contractedChild, view.contractedChild, 0) + + // Then: the contentView DOESN'T propagates the event to its parent + verify(fakeParent, never()).notifySubtreeAccessibilityStateChanged(any(), any(), anyInt()) + } + private fun createMockContainingNotification(notificationEntry: NotificationEntry) = mock<ExpandableNotificationRow>().apply { whenever(this.entry).thenReturn(notificationEntry) @@ -597,7 +630,7 @@ class NotificationContentViewTest : SysuiTestCase() { } private fun createContentView( - isSystemExpanded: Boolean, + isSystemExpanded: Boolean = false, contractedView: View = createViewWithHeight(contractedHeight), expandedView: View = createViewWithHeight(expandedHeight), headsUpView: View = createViewWithHeight(contractedHeight), @@ -647,5 +680,5 @@ private fun NotificationContentView.mockRequestLayout() { } private fun NotificationContentView.clearInvocations() { - Mockito.clearInvocations(contractedWrapper, expandedWrapper, headsUpWrapper) + clearInvocations(contractedWrapper, expandedWrapper, headsUpWrapper) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index 83ba68460aa5..a1721208b2f2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -626,8 +626,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testClearNotifications_clearAllInProgress() { - mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false); - ExpandableNotificationRow row = createClearableRow(); when(row.getEntry().hasFinishedInitialization()).thenReturn(true); doReturn(true).when(mStackScroller).isVisible(row); @@ -672,8 +670,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testAddNotificationUpdatesSpeedBumpIndex() { - mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false); - // initial state calculated == 0 assertEquals(0, mStackScroller.getSpeedBumpIndex()); @@ -690,8 +686,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testAddAmbientNotificationNoSpeedBumpUpdate() { - mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false); - // initial state calculated == 0 assertEquals(0, mStackScroller.getSpeedBumpIndex()); @@ -708,8 +702,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Test public void testRemoveNotificationUpdatesSpeedBump() { - mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false); - // initial state calculated == 0 assertEquals(0, mStackScroller.getSpeedBumpIndex()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java index 3556703a2fa8..4dc4798caa8c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java @@ -84,7 +84,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { LogBuffer logBuffer = FakeLogBuffer.Factory.Companion.create(); mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm(logBuffer); when(mResources.getDimensionPixelSize(anyInt())).thenReturn(0); - mClockPositionAlgorithm.loadDimens(mResources); + mClockPositionAlgorithm.loadDimens(mContext, mResources); mClockPosition = new KeyguardClockPositionAlgorithm.Result(); } @@ -297,7 +297,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { .thenReturn(100); when(mResources.getDimensionPixelSize(R.dimen.large_screen_shade_header_height)) .thenReturn(70); - mClockPositionAlgorithm.loadDimens(mResources); + mClockPositionAlgorithm.loadDimens(mContext, mResources); givenLockScreen(); mIsSplitShade = true; // WHEN the position algorithm is run @@ -589,7 +589,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private void setSplitShadeTopMargin(int value) { when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin)) .thenReturn(value); - mClockPositionAlgorithm.loadDimens(mResources); + mClockPositionAlgorithm.loadDimens(mContext, mResources); } private void givenHighestBurnInOffset() { @@ -603,7 +603,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase { private void givenMaxBurnInOffset(int offset) { when(mResources.getDimensionPixelSize(R.dimen.burn_in_prevention_offset_y_clock)) .thenReturn(offset); - mClockPositionAlgorithm.loadDimens(mResources); + mClockPositionAlgorithm.loadDimens(mContext, mResources); } private void givenAOD() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt deleted file mode 100644 index 91c233a4177d..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.pipeline.mobile.data.repository - -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.statusbar.policy.DeviceProvisionedController -import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener -import com.android.systemui.util.mockito.argumentCaptor -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.cancel -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.runBlocking -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations - -@SmallTest -class UserSetupRepositoryTest : SysuiTestCase() { - private lateinit var underTest: UserSetupRepository - @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController - private val scope = CoroutineScope(IMMEDIATE) - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - underTest = - UserSetupRepositoryImpl( - deviceProvisionedController, - IMMEDIATE, - scope, - ) - } - - @After - fun tearDown() { - scope.cancel() - } - - @Test - fun testUserSetup_defaultFalse() = - runBlocking(IMMEDIATE) { - var latest: Boolean? = null - - val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this) - - assertThat(latest).isFalse() - - job.cancel() - } - - @Test - fun testUserSetup_updatesOnChange() = - runBlocking(IMMEDIATE) { - var latest: Boolean? = null - - val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this) - - whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true) - val callback = getDeviceProvisionedListener() - callback.onUserSetupChanged() - - assertThat(latest).isTrue() - - job.cancel() - } - - private fun getDeviceProvisionedListener(): DeviceProvisionedListener { - val captor = argumentCaptor<DeviceProvisionedListener>() - verify(deviceProvisionedController).addCallback(captor.capture()) - return captor.value!! - } - - companion object { - private val IMMEDIATE = Dispatchers.Main.immediate - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index 2060288c28a4..0b14be1eefbd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -31,10 +31,10 @@ import com.android.systemui.log.table.TableLogBuffer import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt index 52fc2589a3f9..889130f47820 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt @@ -30,7 +30,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor @@ -39,6 +38,7 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconMod import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt index 44fa13283991..147efcbd67c4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt @@ -42,7 +42,6 @@ import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.Airpla import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel @@ -51,6 +50,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt index a906a8953e02..02e6fd5a9d6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt @@ -31,7 +31,7 @@ import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE import android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN import android.telephony.satellite.SatelliteManager.SatelliteException -import android.telephony.satellite.SatelliteStateCallback +import android.telephony.satellite.SatelliteModemStateCallback import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue @@ -106,7 +106,7 @@ class DeviceBasedSatelliteRepositoryImplTest : SysuiTestCase() { val latest by collectLastValue(underTest.connectionState) runCurrent() val callback = - withArgCaptor<SatelliteStateCallback> { + withArgCaptor<SatelliteModemStateCallback> { verify(satelliteManager).registerForSatelliteModemStateChanged(any(), capture()) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt index 89842d6274e9..f63f79ff9835 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt @@ -25,6 +25,7 @@ import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase import com.android.systemui.collectLastValue import com.android.systemui.collectValues +import com.android.systemui.communal.dagger.CommunalModule import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState @@ -58,6 +59,7 @@ class CollapsedStatusBarViewModelImplTest : SysuiTestCase() { modules = [ SysUITestModule::class, + CommunalModule::class, ] ) interface TestComponent : SysUITestComponent<CollapsedStatusBarViewModelImpl> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt index 1bdf64434fcb..0cb3329dcb4d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt @@ -35,7 +35,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy @@ -48,6 +47,7 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.util.CarrierConfigTracker import com.android.systemui.util.mockito.mock import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java index 1dab84eb6e6a..cb6ce68aaf80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.policy; import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -214,7 +215,8 @@ public class SecurityControllerTest extends SysuiTestCase { public void testNetworkRequest() { verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat( (NetworkRequest request) -> - request.equals(new NetworkRequest.Builder().clearCapabilities().build()) + request.equals(new NetworkRequest.Builder() + .clearCapabilities().addTransportType(TRANSPORT_VPN).build()) ), any(NetworkCallback.class)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt index 6714c94b017c..fb5375a1ab83 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserSwitcherInteractorTest.kt @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.UiEventLogger import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback +import com.android.systemui.Flags as AConfigFlags import com.android.systemui.GuestResetOrExitSessionReceiver import com.android.systemui.GuestResumeSessionReceiver import com.android.systemui.SysuiTestCase @@ -121,6 +122,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() { ) utils.featureFlags.set(Flags.FULL_SCREEN_USER_SWITCHER, false) + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_SWITCH_USER_ON_BG) spyContext = spy(context) keyguardReply = KeyguardInteractorFactory.create(featureFlags = utils.featureFlags) keyguardRepository = keyguardReply.repository @@ -172,6 +174,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() { userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) underTest.onRecordSelected(UserRecord(info = userInfos[1]), dialogShower) + runCurrent() verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.SWITCH_TO_USER_FROM_USER_SWITCHER) @@ -191,6 +194,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() { userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) underTest.onRecordSelected(UserRecord(info = userInfos.last())) + runCurrent() verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.SWITCH_TO_GUEST_FROM_USER_SWITCHER) @@ -218,6 +222,7 @@ class UserSwitcherInteractorTest : SysuiTestCase() { userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true)) underTest.onRecordSelected(UserRecord(info = userInfos.last())) + runCurrent() verify(uiEventLogger, times(1)) .log(MultiUserActionsEvent.SWITCH_TO_RESTRICTED_USER_FROM_USER_SWITCHER) diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 814ea19a7dcb..8920d4df2a91 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -99,6 +99,8 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository; import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor; import com.android.systemui.dump.DumpManager; import com.android.systemui.flags.FakeFeatureFlags; @@ -111,6 +113,7 @@ import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepos import com.android.systemui.keyguard.data.repository.InWindowLauncherUnlockAnimationRepository; import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; +import com.android.systemui.keyguard.domain.interactor.GlanceableHubTransitions; import com.android.systemui.keyguard.domain.interactor.InWindowLauncherUnlockAnimationInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; @@ -126,6 +129,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlags; import com.android.systemui.scene.shared.logger.SceneLogger; import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.settings.UserTracker; +import com.android.systemui.shade.LargeScreenHeaderHelper; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.ShadeController; @@ -159,7 +163,6 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.Share import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.ScreenOffAnimationController; -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -168,6 +171,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository; +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository; import com.android.systemui.user.domain.interactor.SelectedUserInteractor; import com.android.systemui.user.domain.interactor.UserSwitcherInteractor; import com.android.systemui.util.FakeEventLog; @@ -349,6 +353,8 @@ public class BubblesTest extends SysuiTestCase { private Display mDefaultDisplay; @Mock private SceneContainerFlags mSceneContainerFlags; + @Mock + private LargeScreenHeaderHelper mLargeScreenHeaderHelper; private final SceneTestUtils mUtils = new SceneTestUtils(this); private final TestScope mTestScope = mUtils.getTestScope(); @@ -436,15 +442,25 @@ public class BubblesTest extends SysuiTestCase { () -> keyguardInteractor, () -> mFromLockscreenTransitionInteractor, () -> mFromPrimaryBouncerTransitionInteractor); + CommunalInteractor communalInteractor = + CommunalInteractorFactory.create().getCommunalInteractor(); mFromLockscreenTransitionInteractor = new FromLockscreenTransitionInteractor( keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, shadeRepository, powerInteractor, + new GlanceableHubTransitions( + mTestScope, + keyguardTransitionInteractor, + keyguardTransitionRepository, + communalInteractor + ), () -> new InWindowLauncherUnlockAnimationInteractor( new InWindowLauncherUnlockAnimationRepository(), @@ -459,6 +475,8 @@ public class BubblesTest extends SysuiTestCase { keyguardTransitionRepository, keyguardTransitionInteractor, mTestScope.getBackgroundScope(), + mUtils.getTestDispatcher(), + mUtils.getTestDispatcher(), keyguardInteractor, featureFlags, mock(KeyguardSecurityModel.class), @@ -490,7 +508,8 @@ public class BubblesTest extends SysuiTestCase { mContext, splitShadeStateController, keyguardInteractor, - deviceEntryUdfpsInteractor), + deviceEntryUdfpsInteractor, + () -> mLargeScreenHeaderHelper), shadeRepository ) ); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt index e24ba265e260..c2dc67319fff 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt @@ -48,6 +48,9 @@ private constructor( @get:[Provides Application] val appScope: CoroutineScope = scope.backgroundScope + @get:[Provides Background] + val bgScope: CoroutineScope = scope.backgroundScope + @Module interface Bindings { @Binds @Main fun bindMainContext(dispatcher: TestDispatcher): CoroutineContext diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt index b28af46835ae..fdb9b30e546e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt @@ -25,6 +25,7 @@ import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardViewController import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.demomode.DemoModeController import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.ScreenLifecycle @@ -111,6 +112,7 @@ data class TestMocksModule( @get:Provides val zenModeController: ZenModeController = mock(), @get:Provides val systemUIDialogManager: SystemUIDialogManager = mock(), @get:Provides val deviceEntryIconTransitions: Set<DeviceEntryIconTransition> = emptySet(), + @get:Provides val communalInteractor: CommunalInteractor = mock(), // log buffers @get:[Provides BroadcastDispatcherLog] diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt new file mode 100644 index 000000000000..4a089d3c6d7c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/DisplayStateInteractorKosmos.kt @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 The Android Open 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.domain.interactor + +import android.content.applicationContext +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayStateRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.util.mockito.mock +import java.util.concurrent.Executor + +val Kosmos.displayStateInteractor by Fixture { + DisplayStateInteractorImpl( + applicationScope = applicationCoroutineScope, + context = applicationContext, + mainExecutor = mock<Executor>(), + displayStateRepository = displayStateRepository, + displayRepository = displayRepository, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt new file mode 100644 index 000000000000..e26206625c6d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/FingerprintPropertyInteractorKosmos.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open 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.domain.interactor + +import android.content.applicationContext +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.fingerprintPropertyInteractor by Fixture { + FingerprintPropertyInteractor( + context = applicationContext, + repository = fingerprintPropertyRepository, + configurationInteractor = configurationInteractor, + displayStateInteractor = displayStateInteractor, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt index ff5179a7042c..8010261934b1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/data/repository/FakeKeyguardBouncerRepository.kt @@ -2,6 +2,7 @@ package com.android.systemui.bouncer.data.repository import com.android.systemui.biometrics.shared.SideFpsControllerRefactor import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants +import com.android.systemui.bouncer.shared.model.BouncerDismissActionModel import com.android.systemui.bouncer.shared.model.BouncerShowMessageModel import com.android.systemui.dagger.SysUISingleton import dagger.Binds @@ -53,6 +54,7 @@ class FakeKeyguardBouncerRepository @Inject constructor() : KeyguardBouncerRepos override val alternateBouncerUIAvailable = _isAlternateBouncerUIAvailable.asStateFlow() private val _sideFpsShowing: MutableStateFlow<Boolean> = MutableStateFlow(false) override val sideFpsShowing: StateFlow<Boolean> = _sideFpsShowing.asStateFlow() + override var bouncerDismissActionModel: BouncerDismissActionModel? = null override fun setPrimaryScrimmed(isScrimmed: Boolean) { _primaryBouncerScrimmed.value = isScrimmed diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryKosmos.kt new file mode 100644 index 000000000000..7946446cb976 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open 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.communal.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.communalMediaRepository: CommunalMediaRepository by + Kosmos.Fixture { fakeCommunalMediaRepository } +val Kosmos.fakeCommunalMediaRepository by Kosmos.Fixture { FakeCommunalMediaRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalRepositoryKosmos.kt new file mode 100644 index 000000000000..be56d2b20ded --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open 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.communal.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.communalRepository: CommunalRepository by Kosmos.Fixture { fakeCommunalRepository } +val Kosmos.fakeCommunalRepository by Kosmos.Fixture { FakeCommunalRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryKosmos.kt new file mode 100644 index 000000000000..5a17f2f857cf --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalWidgetRepositoryKosmos.kt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open 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.communal.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope + +var Kosmos.communalWidgetRepository: CommunalWidgetRepository by + Kosmos.Fixture { fakeCommunalWidgetRepository } +val Kosmos.fakeCommunalWidgetRepository by + Kosmos.Fixture { FakeCommunalWidgetRepository(applicationCoroutineScope) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt index eb287ee522c0..95ff889177b8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorFactory.kt @@ -35,7 +35,8 @@ object CommunalInteractorFactory { @JvmStatic fun create( testScope: TestScope = TestScope(), - communalRepository: FakeCommunalRepository = FakeCommunalRepository(), + communalRepository: FakeCommunalRepository = + FakeCommunalRepository(testScope.backgroundScope), widgetRepository: FakeCommunalWidgetRepository = FakeCommunalWidgetRepository(testScope.backgroundScope), mediaRepository: FakeCommunalMediaRepository = FakeCommunalMediaRepository(), @@ -51,6 +52,7 @@ object CommunalInteractorFactory { communalRepository = communalRepository, ) return WithDependencies( + testScope, communalRepository, widgetRepository, mediaRepository, @@ -74,6 +76,7 @@ object CommunalInteractorFactory { } data class WithDependencies( + val testScope: TestScope, val communalRepository: FakeCommunalRepository, val widgetRepository: FakeCommunalWidgetRepository, val mediaRepository: FakeCommunalMediaRepository, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt new file mode 100644 index 000000000000..048ea3c25388 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open 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.display.data.repository + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.displayRepository by Fixture { FakeDisplayRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt new file mode 100644 index 000000000000..4a71a099d0d5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open 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.display.data.repository + +import com.android.systemui.biometrics.data.repository.FakeDisplayStateRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture + +val Kosmos.displayStateRepository by Fixture { FakeDisplayStateRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt index 1d44929a20f0..93e0b418d076 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt @@ -62,6 +62,10 @@ class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() : fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) { _authenticationStatus.value = status } + + fun setShouldUpdateIndicatorVisibility(shouldUpdateIndicatorVisibility: Boolean) { + _shouldUpdateIndicatorVisibility.value = shouldUpdateIndicatorVisibility + } } @Module diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt index a94ca291298d..0c1dbfebfb34 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt @@ -147,7 +147,6 @@ class FakeKeyguardTransitionRepository @Inject constructor() : KeyguardTransitio ) } } - _transitions.emit(step) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/CommunalInteractorKosmos.kt new file mode 100644 index 000000000000..59f0ec3cd3a5 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/CommunalInteractorKosmos.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.domain.interactor + +import android.appwidget.AppWidgetHost +import com.android.systemui.communal.data.repository.communalMediaRepository +import com.android.systemui.communal.data.repository.communalRepository +import com.android.systemui.communal.data.repository.communalWidgetRepository +import com.android.systemui.communal.domain.interactor.CommunalInteractor +import com.android.systemui.communal.widgets.EditWidgetsActivityStarter +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.smartspace.data.repository.smartspaceRepository +import org.mockito.Mockito.mock + +val Kosmos.communalInteractor by + Kosmos.Fixture { + CommunalInteractor( + communalRepository = communalRepository, + widgetRepository = communalWidgetRepository, + mediaRepository = communalMediaRepository, + smartspaceRepository = smartspaceRepository, + keyguardInteractor = keyguardInteractor, + appWidgetHost = mock(AppWidgetHost::class.java), + editWidgetsActivityStarter = mock(EditWidgetsActivityStarter::class.java), + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt index b03d0b822161..3b38342119e6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt @@ -20,6 +20,7 @@ import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.shade.data.repository.shadeRepository import dagger.Lazy @@ -30,10 +31,13 @@ val Kosmos.fromLockscreenTransitionInteractor by transitionRepository = keyguardTransitionRepository, transitionInteractor = keyguardTransitionInteractor, scope = applicationCoroutineScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, flags = featureFlagsClassic, shadeRepository = shadeRepository, powerInteractor = powerInteractor, + glanceableHubTransitions = glanceableHubTransitions, inWindowLauncherUnlockAnimationInteractor = Lazy { inWindowLauncherUnlockAnimationInteractor }, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt index ade3e1a82297..97536e20cb0a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.flags.featureFlagsClassic import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testDispatcher import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor @@ -30,6 +31,8 @@ val Kosmos.fromPrimaryBouncerTransitionInteractor by transitionRepository = keyguardTransitionRepository, transitionInteractor = keyguardTransitionInteractor, scope = applicationCoroutineScope, + bgDispatcher = testDispatcher, + mainDispatcher = testDispatcher, keyguardInteractor = keyguardInteractor, flags = featureFlagsClassic, keyguardSecurityModel = keyguardSecurityModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt new file mode 100644 index 000000000000..294b5ba474c3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.domain.interactor + +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope + +val Kosmos.glanceableHubTransitions by + Kosmos.Fixture { + GlanceableHubTransitions( + scope = applicationCoroutineScope, + transitionRepository = keyguardTransitionRepository, + transitionInteractor = keyguardTransitionInteractor, + communalInteractor = communalInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt index 8d6529a114b8..dad1887cbd85 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/KeyguardTransitionAnimationFlowKosmos.kt @@ -19,6 +19,7 @@ package com.android.systemui.keyguard.ui import com.android.keyguard.logging.keyguardTransitionAnimationLogger +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.applicationCoroutineScope @@ -27,6 +28,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.keyguardTransitionAnimationFlow by Fixture { KeyguardTransitionAnimationFlow( scope = applicationCoroutineScope, + transitionInteractor = keyguardTransitionInteractor, logger = keyguardTransitionAnimationLogger, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt index d9c6e4f1f605..3ed9392bab2a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToAodTransitionViewModel by Fixture { AlternateBouncerToAodTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt index e4821b04fcef..c909dd6ffdd5 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToGoneTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerToGoneTransitionViewModel by Fixture { AlternateBouncerToGoneTransitionViewModel( - interactor = keyguardTransitionInteractor, bouncerToGoneFlows = bouncerToGoneFlows, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..2d1f836d455d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToPrimaryBouncerTransitionViewModelKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2023 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.alternateBouncerToPrimaryBouncerTransitionViewModel by Fixture { + AlternateBouncerToPrimaryBouncerTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt index 9f0466dda51e..b4f1218617a2 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -28,7 +27,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.alternateBouncerViewModel by Fixture { AlternateBouncerViewModel( statusBarKeyguardViewManager = statusBarKeyguardViewManager, - transitionInteractor = keyguardTransitionInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt index 44e542660971..b6f278c1b466 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToGoneTransitionViewModel by Fixture { AodToGoneTransitionViewModel( - interactor = keyguardTransitionInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt index b5a5f039200f..733340c67e55 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToLockscreenTransitionViewModel by Fixture { AodToLockscreenTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt index 27ad0f0f01e3..8d066fc05996 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.aodToOccludedTransitionViewModel by Fixture { AodToOccludedTransitionViewModel( - interactor = keyguardTransitionInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt index 6ffcc9a03b05..c71c1c3ea5f0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsKosmos.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor import com.android.systemui.flags.featureFlagsClassic -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -31,7 +30,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.bouncerToGoneFlows by Fixture { BouncerToGoneFlows( - interactor = keyguardTransitionInteractor, statusBarStateController = sysuiStatusBarStateController, primaryBouncerInteractor = primaryBouncerInteractor, keyguardDismissActionInteractor = mock(), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt index 4bfe4f571b05..4f638d0e4a38 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt @@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.applicationContext import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor -import com.android.systemui.common.ui.data.repository.configurationRepository +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.kosmos.Kosmos @@ -29,7 +29,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.deviceEntryForegroundIconViewModel by Fixture { DeviceEntryForegroundViewModel( context = applicationContext, - configurationRepository = configurationRepository, + configurationInteractor = configurationInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, transitionInteractor = keyguardTransitionInteractor, deviceEntryIconViewModel = deviceEntryIconViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..400a0d87f041 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.dozingToLockscreenTransitionViewModel by Fixture { + DozingToLockscreenTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..28fce77b75b7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToLockscreenTransitionViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +val Kosmos.glanceableHubToLockscreenTransitionViewModel by Fixture { + GlanceableHubToLockscreenTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt index 00ece1482236..19e4241c62fa 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToAodTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.goneToAodTransitionViewModel by Fixture { GoneToAodTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt index 073b34bcf277..b267a962a1ff 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDreamingTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.goneToDreamingTransitionViewModel by Fixture { GoneToDreamingTransitionViewModel( - interactor = keyguardTransitionInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index 933f50c36b7b..5564767e0715 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -39,5 +39,7 @@ val Kosmos.keyguardRootViewModel by Fixture { screenOffAnimationController = screenOffAnimationController, aodBurnInViewModel = aodBurnInViewModel, aodAlphaViewModel = aodAlphaViewModel, + lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel, + glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt index 7865f71ead83..07b4cd4f3251 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToAodTransitionViewModel by Fixture { LockscreenToAodTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, shadeDependentFlows = shadeDependentFlows, animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt index b9f4b71d24d6..56d5ff6e30eb 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToDreamingTransitionViewModel by Fixture { LockscreenToDreamingTransitionViewModel( - interactor = keyguardTransitionInteractor, shadeDependentFlows = shadeDependentFlows, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..9fe4ea347f63 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGlanceableHubTransitionViewModelKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +val Kosmos.lockscreenToGlanceableHubTransitionViewModel by Fixture { + LockscreenToGlanceableHubTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt index 475aa2de3f9b..1b2337fedf6a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToGoneTransitionViewModel by Fixture { LockscreenToGoneTransitionViewModel( - interactor = keyguardTransitionInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt index 8541a4fe7096..9953d39e9a49 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToOccludedTransitionViewModel by Fixture { LockscreenToOccludedTransitionViewModel( - interactor = keyguardTransitionInteractor, shadeDependentFlows = shadeDependentFlows, configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt index 65c47fc9c2c7..f094f22c9f50 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelKosmos.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -26,7 +25,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.lockscreenToPrimaryBouncerTransitionViewModel by Fixture { LockscreenToPrimaryBouncerTransitionViewModel( - interactor = keyguardTransitionInteractor, shadeDependentFlows = shadeDependentFlows, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt index ddde5498d544..b7867b6cabde 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.occludedToAodTransitionViewModel by Fixture { OccludedToAodTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt index 93ecb7968ee2..e6651a44236f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelKosmos.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -28,7 +27,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi var Kosmos.occludedToLockscreenTransitionViewModel by Fixture { OccludedToLockscreenTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt index a7f29d637281..8d887309f576 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToAodTransitionViewModel by Fixture { PrimaryBouncerToAodTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt index ace6ae3e3eec..ab28d0d670ef 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelKosmos.kt @@ -20,7 +20,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor import com.android.systemui.flags.featureFlagsClassic -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -30,7 +29,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToGoneTransitionViewModel by Fixture { PrimaryBouncerToGoneTransitionViewModel( - interactor = keyguardTransitionInteractor, statusBarStateController = sysuiStatusBarStateController, primaryBouncerInteractor = primaryBouncerInteractor, keyguardDismissActionInteractor = mock(), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt index 3bbabf713b91..85662512a5ee 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelKosmos.kt @@ -19,7 +19,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor -import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture @@ -27,7 +26,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi val Kosmos.primaryBouncerToLockscreenTransitionViewModel by Fixture { PrimaryBouncerToLockscreenTransitionViewModel( - interactor = keyguardTransitionInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt index 1185f2edef3b..0307c414351f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt @@ -35,14 +35,21 @@ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler { mutableInputs.add(Input.Intent(view, intent)) } - override fun handle(view: View?, pendingIntent: PendingIntent) { - mutableInputs.add(Input.PendingIntent(view, pendingIntent)) + override fun handle( + view: View?, + pendingIntent: PendingIntent, + requestLaunchingDefaultActivity: Boolean + ) { + mutableInputs.add(Input.PendingIntent(view, pendingIntent, requestLaunchingDefaultActivity)) } sealed interface Input { data class Intent(val view: View?, val intent: android.content.Intent) : Input - data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) : - Input + data class PendingIntent( + val view: View?, + val pendingIntent: android.app.PendingIntent, + val requestLaunchingDefaultActivity: Boolean + ) : Input } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/LargeScreenHeaderHelperKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/LargeScreenHeaderHelperKosmos.kt new file mode 100644 index 000000000000..d3e757469a99 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/LargeScreenHeaderHelperKosmos.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 The Android Open 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.shade + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.util.mockito.mock + +var Kosmos.largeScreenHeaderHelper by Fixture { mockLargeScreenHeaderHelper } +val Kosmos.mockLargeScreenHeaderHelper by Fixture { mock<LargeScreenHeaderHelper>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt index 7da57f024ec7..afd37b3f92dc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt @@ -29,8 +29,8 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.statusbar.phone.dozeParameters -import com.android.systemui.statusbar.pipeline.mobile.data.repository.userSetupRepository import com.android.systemui.statusbar.policy.data.repository.deviceProvisioningRepository +import com.android.systemui.statusbar.policy.data.repository.userSetupRepository import com.android.systemui.user.domain.interactor.userSwitcherInteractor var Kosmos.baseShadeInteractor: BaseShadeInteractor by diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt new file mode 100644 index 000000000000..e671d4527be1 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open 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.smartspace.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.smartspaceRepository: SmartspaceRepository by Kosmos.Fixture { fakeSmartspaceRepository } +val Kosmos.fakeSmartspaceRepository by Kosmos.Fixture { FakeSmartspaceRepository() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt index f1e6a053643f..f1e6a053643f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt new file mode 100644 index 000000000000..c416ea1c1b39 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.data.repository + +import kotlinx.coroutines.flow.MutableStateFlow + +class FakeRemoteInputRepository : RemoteInputRepository { + override val isRemoteInputActive = MutableStateFlow(false) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt new file mode 100644 index 000000000000..1684efba2ca2 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.data.repository + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.remoteInputRepository: RemoteInputRepository by + Kosmos.Fixture { fakeRemoteInputRepository } +val Kosmos.fakeRemoteInputRepository by Kosmos.Fixture { FakeRemoteInputRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt new file mode 100644 index 000000000000..07b39dc87a9a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.data.repository.remoteInputRepository + +val Kosmos.remoteInputInteractor by Kosmos.Fixture { RemoteInputInteractor(remoteInputRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt index 13d577bde711..8909d751227a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/domain/interactor/SharedNotificationContainerInteractorKosmos.kt @@ -21,6 +21,7 @@ import com.android.systemui.common.ui.data.repository.configurationRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.policy.splitShadeStateController val Kosmos.sharedNotificationContainerInteractor by @@ -31,5 +32,6 @@ val Kosmos.sharedNotificationContainerInteractor by splitShadeStateController = splitShadeStateController, keyguardInteractor = keyguardInteractor, deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + largeScreenHeaderHelperLazy = { largeScreenHeaderHelper } ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt index 44f31343b06d..f5a4c034d836 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt @@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.activeNotif import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel +import com.android.systemui.statusbar.policy.domain.interactor.userSetupInteractor import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor import java.util.Optional diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt index 549929c2c04a..6e2d12ac06b6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt @@ -15,7 +15,7 @@ */ package com.android.systemui.statusbar.pipeline.mobile.data -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepositoryModule +import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepositoryModule import dagger.Module @Module(includes = [FakeUserSetupRepositoryModule::class]) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt index 5f4d7bf6f371..5f4d7bf6f371 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt index a9ee4055d1a8..de6c87c2b515 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt @@ -76,8 +76,8 @@ class FakeMobileIconsInteractor( private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON) override val defaultMobileIconGroup = _defaultMobileIconGroup - private val _isUserSetup = MutableStateFlow(true) - override val isUserSetup = _isUserSetup + private val _isUserSetUp = MutableStateFlow(true) + override val isUserSetUp = _isUserSetUp override val isForceHidden = MutableStateFlow(false) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt index 021e7dff9120..ac90a45450d0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt @@ -77,6 +77,8 @@ class FakeSecurityController( override fun isVpnBranded(): Boolean = fakeState.isVpnBranded + override fun isVpnValidated(): Boolean = fakeState.isVpnValidated + override fun getPrimaryVpnName(): String? = fakeState.primaryVpnName override fun getWorkProfileVpnName(): String? = fakeState.workProfileVpnName @@ -110,6 +112,7 @@ class FakeSecurityController( var isVpnEnabled: Boolean = false, var isVpnRestricted: Boolean = false, var isVpnBranded: Boolean = false, + var isVpnValidated: Boolean = false, var primaryVpnName: String? = null, var workProfileVpnName: String? = null, var hasCACertInCurrentUser: Boolean = false, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt index 55e81bbc77e7..76a9861f5a6f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.mobile.data.repository +package com.android.systemui.statusbar.policy.data.repository import com.android.systemui.dagger.SysUISingleton import dagger.Binds @@ -26,10 +26,10 @@ import kotlinx.coroutines.flow.MutableStateFlow @SysUISingleton class FakeUserSetupRepository @Inject constructor() : UserSetupRepository { private val _isUserSetup: MutableStateFlow<Boolean> = MutableStateFlow(true) - override val isUserSetupFlow = _isUserSetup + override val isUserSetUp = _isUserSetup - fun setUserSetup(setup: Boolean) { - _isUserSetup.value = setup + fun setUserSetUp(isSetUp: Boolean) { + _isUserSetup.value = isSetUp } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt index 7b9634a7abb5..a1c5b9aef54e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.pipeline.mobile.data.repository +package com.android.systemui.statusbar.policy.data.repository import com.android.systemui.kosmos.Kosmos diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt new file mode 100644 index 000000000000..83f4939cee1f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.policy.data.repository.userSetupRepository + +val Kosmos.userSetupInteractor by Kosmos.Fixture { UserSetupInteractor(userSetupRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java index 76199e3168da..791165d97795 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeSecurityController.java @@ -109,6 +109,11 @@ public class FakeSecurityController extends BaseLeakChecker<SecurityControllerCa } @Override + public boolean isVpnValidated() { + return false; + } + + @Override public String getPrimaryVpnName() { return null; } diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp index e52cefb2d7e4..81fd8ce12f05 100644 --- a/packages/SystemUI/unfold/Android.bp +++ b/packages/SystemUI/unfold/Android.bp @@ -39,7 +39,4 @@ android_library { sdk_version: "current", min_sdk_version: "current", plugins: ["dagger2-compiler"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } diff --git a/packages/SystemUI/unfold/lint-baseline.xml b/packages/SystemUI/unfold/lint-baseline.xml deleted file mode 100644 index 449ed2e60853..000000000000 --- a/packages/SystemUI/unfold/lint-baseline.xml +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev"> -</issues> diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java index 1fc74f704f62..67a7d121ea17 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java @@ -16,6 +16,8 @@ package com.android.vpndialogs; +import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import android.content.DialogInterface; import android.net.VpnManager; import android.os.Bundle; @@ -87,6 +89,7 @@ public class ManageDialog extends AlertActivity implements mAlertParams.mNegativeButtonListener = this; mAlertParams.mView = view; setupAlert(); + getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); if (mHandler == null) { mHandler = new Handler(this); diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index b403a7fe8f12..7f542d130cf7 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -408,5 +408,9 @@ message SystemMessage { // Notify the user about external display events related to screenshot. // Package: com.android.systemui NOTE_GLOBAL_SCREENSHOT_EXTERNAL_DISPLAY = 1008; + + // Notify the user that accessibility floating menu is hidden. + // Package: com.android.systemui + NOTE_A11Y_FLOATING_MENU_HIDDEN = 1009; } } diff --git a/services/Android.bp b/services/Android.bp index 0b484f473d36..7e8333c7ba5f 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -148,9 +148,6 @@ filegroup { java_library { name: "Slogf", srcs: ["core/java/com/android/server/utils/Slogf.java"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } // merge all required services into one jar diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp index a3546716d5ca..69cc68a55108 100644 --- a/services/accessibility/Android.bp +++ b/services/accessibility/Android.bp @@ -22,6 +22,7 @@ java_library_static { lint: { error_checks: ["MissingPermissionAnnotation"], baseline_filename: "lint-baseline.xml", + }, srcs: [ ":services.accessibility-sources", @@ -50,9 +51,6 @@ java_library_static { libs: [ "androidx.annotation_annotation", ], - lint: { - baseline_filename: "lint-baseline.xml", - }, } aconfig_declarations { diff --git a/services/accessibility/lint-baseline.xml b/services/accessibility/lint-baseline.xml index 6bec8cf5f018..b808219ef9c6 100644 --- a/services/accessibility/lint-baseline.xml +++ b/services/accessibility/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="SimpleManualPermissionEnforcement" @@ -23,4 +23,4 @@ column="9"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index cab2d74c27d1..5407af7bda44 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -362,6 +362,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); packageFilter.addDataScheme("package"); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, packageFilter, null, mCallbackHandler); @@ -402,6 +403,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku boolean added = false; boolean changed = false; boolean componentsModified = false; + int clearedUid = -1; final String pkgList[]; switch (action) { @@ -416,6 +418,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); break; + case Intent.ACTION_PACKAGE_DATA_CLEARED: + pkgList = null; + clearedUid = intent.getIntExtra(Intent.EXTRA_UID, -1); + break; default: { Uri uri = intent.getData(); if (uri == null) { @@ -430,7 +436,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); } } - if (pkgList == null || pkgList.length == 0) { + if ((pkgList == null || pkgList.length == 0) && clearedUid == -1) { return; } @@ -461,6 +467,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } } + } else if (clearedUid != -1) { + componentsModified |= clearPreviewsForUidLocked(clearedUid); } else { // If the package is being updated, we'll receive a PACKAGE_ADDED // shortly, otherwise it is removed permanently. @@ -486,6 +494,19 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } + @GuardedBy("mLock") + private boolean clearPreviewsForUidLocked(int clearedUid) { + boolean changed = false; + final int providerCount = mProviders.size(); + for (int i = 0; i < providerCount; i++) { + Provider provider = mProviders.get(i); + if (provider.id.uid == clearedUid) { + changed |= provider.clearGeneratedPreviewsLocked(); + } + } + return changed; + } + /** * Reload all widgets' masked state for the given user and its associated profiles, including * due to user not being available and package suspension. @@ -3904,6 +3925,124 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } + @Override + @Nullable + public RemoteViews getWidgetPreview(@NonNull String callingPackage, + @NonNull ComponentName providerComponent, int profileId, + @AppWidgetProviderInfo.CategoryFlags int widgetCategory) { + final int callingUserId = UserHandle.getCallingUserId(); + if (DEBUG) { + Slog.i(TAG, "getWidgetPreview() " + callingUserId); + } + mSecurityPolicy.enforceCallFromPackage(callingPackage); + ensureWidgetCategoryCombinationIsValid(widgetCategory); + + synchronized (mLock) { + ensureGroupStateLoadedLocked(profileId); + final int providerCount = mProviders.size(); + for (int i = 0; i < providerCount; i++) { + Provider provider = mProviders.get(i); + final ComponentName componentName = provider.id.componentName; + if (provider.zombie || !providerComponent.equals(componentName)) { + continue; + } + + final AppWidgetProviderInfo info = provider.getInfoLocked(mContext); + final int providerProfileId = info.getProfile().getIdentifier(); + if (providerProfileId != profileId) { + continue; + } + + // Allow access to this provider if it is from the calling package or the caller has + // BIND_APPWIDGET permission. + final int callingUid = Binder.getCallingUid(); + final String providerPackageName = componentName.getPackageName(); + final boolean providerIsInCallerProfile = + mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( + providerPackageName, providerProfileId); + final boolean shouldFilterAppAccess = mPackageManagerInternal.filterAppAccess( + providerPackageName, callingUid, providerProfileId); + final boolean providerIsInCallerPackage = + mSecurityPolicy.isProviderInPackageForUid(provider, callingUid, + callingPackage); + final boolean hasBindAppWidgetPermission = + mSecurityPolicy.hasCallerBindPermissionOrBindWhiteListedLocked( + callingPackage); + if (providerIsInCallerProfile && !shouldFilterAppAccess + && (providerIsInCallerPackage || hasBindAppWidgetPermission)) { + return provider.getGeneratedPreviewLocked(widgetCategory); + } + } + } + throw new IllegalArgumentException( + providerComponent + " is not a valid AppWidget provider"); + } + + @Override + public void setWidgetPreview(@NonNull ComponentName providerComponent, + @AppWidgetProviderInfo.CategoryFlags int widgetCategories, + @NonNull RemoteViews preview) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG) { + Slog.i(TAG, "setWidgetPreview() " + userId); + } + + // Make sure callers only set previews for their own package. + mSecurityPolicy.enforceCallFromPackage(providerComponent.getPackageName()); + + ensureWidgetCategoryCombinationIsValid(widgetCategories); + + synchronized (mLock) { + ensureGroupStateLoadedLocked(userId); + + final ProviderId providerId = new ProviderId(Binder.getCallingUid(), providerComponent); + final Provider provider = lookupProviderLocked(providerId); + if (provider == null) { + throw new IllegalArgumentException( + providerComponent + " is not a valid AppWidget provider"); + } + provider.setGeneratedPreviewLocked(widgetCategories, preview); + scheduleNotifyGroupHostsForProvidersChangedLocked(userId); + } + } + + @Override + public void removeWidgetPreview(@NonNull ComponentName providerComponent, + @AppWidgetProviderInfo.CategoryFlags int widgetCategories) { + final int userId = UserHandle.getCallingUserId(); + if (DEBUG) { + Slog.i(TAG, "removeWidgetPreview() " + userId); + } + + // Make sure callers only remove previews for their own package. + mSecurityPolicy.enforceCallFromPackage(providerComponent.getPackageName()); + + ensureWidgetCategoryCombinationIsValid(widgetCategories); + synchronized (mLock) { + ensureGroupStateLoadedLocked(userId); + + final ProviderId providerId = new ProviderId(Binder.getCallingUid(), providerComponent); + final Provider provider = lookupProviderLocked(providerId); + if (provider == null) { + throw new IllegalArgumentException( + providerComponent + " is not a valid AppWidget provider"); + } + final boolean changed = provider.removeGeneratedPreviewLocked(widgetCategories); + if (changed) scheduleNotifyGroupHostsForProvidersChangedLocked(userId); + } + } + + private static void ensureWidgetCategoryCombinationIsValid(int widgetCategories) { + int validCategories = AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN + | AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD + | AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX; + int invalid = ~validCategories; + if ((widgetCategories & invalid) != 0) { + throw new IllegalArgumentException(widgetCategories + + " is not a valid widget category combination"); + } + } + private final class CallbackHandler extends Handler { public static final int MSG_NOTIFY_UPDATE_APP_WIDGET = 1; public static final int MSG_NOTIFY_PROVIDER_CHANGED = 2; @@ -4201,6 +4340,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku ArrayList<Widget> widgets = new ArrayList<>(); PendingIntent broadcast; String infoTag; + SparseArray<RemoteViews> generatedPreviews = new SparseArray<>(3); + private static final int[] WIDGET_CATEGORY_FLAGS = new int[]{ + AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, + AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, + AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX, + }; boolean zombie; // if we're in safe mode, don't prune this just because nobody references it @@ -4234,7 +4379,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return false; } - @GuardedBy("AppWidgetServiceImpl.mLock") + @GuardedBy("this.mLock") public AppWidgetProviderInfo getInfoLocked(Context context) { if (!mInfoParsed) { // parse @@ -4250,6 +4395,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } if (newInfo != null) { info = newInfo; + updateGeneratedPreviewCategoriesLocked(); } } mInfoParsed = true; @@ -4279,6 +4425,62 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku mInfoParsed = true; } + @GuardedBy("this.mLock") + @Nullable + public RemoteViews getGeneratedPreviewLocked( + @AppWidgetProviderInfo.CategoryFlags int widgetCategories) { + for (int i = 0; i < generatedPreviews.size(); i++) { + if ((widgetCategories & generatedPreviews.keyAt(i)) != 0) { + return generatedPreviews.valueAt(i); + } + } + return null; + } + + @GuardedBy("this.mLock") + public void setGeneratedPreviewLocked( + @AppWidgetProviderInfo.CategoryFlags int widgetCategories, + @NonNull RemoteViews preview) { + for (int flag : WIDGET_CATEGORY_FLAGS) { + if ((widgetCategories & flag) != 0) { + generatedPreviews.put(flag, preview); + } + } + updateGeneratedPreviewCategoriesLocked(); + } + + @GuardedBy("this.mLock") + public boolean removeGeneratedPreviewLocked(int widgetCategories) { + boolean changed = false; + for (int flag : WIDGET_CATEGORY_FLAGS) { + if ((widgetCategories & flag) != 0) { + changed |= generatedPreviews.removeReturnOld(flag) != null; + } + } + if (changed) { + updateGeneratedPreviewCategoriesLocked(); + } + return changed; + } + + @GuardedBy("this.mLock") + public boolean clearGeneratedPreviewsLocked() { + if (generatedPreviews.size() > 0) { + generatedPreviews.clear(); + updateGeneratedPreviewCategoriesLocked(); + return true; + } + return false; + } + + @GuardedBy("this.mLock") + private void updateGeneratedPreviewCategoriesLocked() { + info.generatedPreviewCategories = 0; + for (int i = 0; i < generatedPreviews.size(); i++) { + info.generatedPreviewCategories |= generatedPreviews.keyAt(i); + } + } + @Override public String toString() { return "Provider{" + id + (zombie ? " Z" : "") + '}'; diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6a81425c1443..a856f424be5c 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -4271,13 +4271,19 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (value != null) { viewState.setCurrentValue(value); } - + boolean isCredmanRequested = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0; if (shouldRequestSecondaryProvider(flags)) { if (requestNewFillResponseOnViewEnteredIfNecessaryLocked( id, viewState, flags)) { Slog.v(TAG, "Started a new fill request for secondary provider."); return; } + + FillResponse response = viewState.getSecondaryResponse(); + if (response != null) { + logPresentationStatsOnViewEntered(response, isCredmanRequested); + } + // If the ViewState is ready to be displayed, onReady() will be called. viewState.update(value, virtualBounds, flags); @@ -4363,15 +4369,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState return; } - if (viewState.getResponse() != null) { - boolean isCredmanRequested = (flags & FLAG_VIEW_REQUESTS_CREDMAN_SERVICE) != 0; - FillResponse response = viewState.getResponse(); - mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId()); - mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested); - mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId( - mFieldClassificationIdSnapshot); - mPresentationStatsEventLogger.maybeSetAvailableCount( - response.getDatasets(), mCurrentViewId); + FillResponse response = viewState.getResponse(); + if (response != null) { + logPresentationStatsOnViewEntered(response, isCredmanRequested); } if (isSameViewEntered) { @@ -4412,6 +4412,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } @GuardedBy("mLock") + private void logPresentationStatsOnViewEntered(FillResponse response, + boolean isCredmanRequested) { + mPresentationStatsEventLogger.maybeSetRequestId(response.getRequestId()); + mPresentationStatsEventLogger.maybeSetIsCredentialRequest(isCredmanRequested); + mPresentationStatsEventLogger.maybeSetFieldClassificationRequestId( + mFieldClassificationIdSnapshot); + mPresentationStatsEventLogger.maybeSetAvailableCount( + response.getDatasets(), mCurrentViewId); + } + + @GuardedBy("mLock") private void hideAugmentedAutofillLocked(@NonNull ViewState viewState) { if ((viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) { diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig index d695d36db0ea..549fa36597b7 100644 --- a/services/backup/flags.aconfig +++ b/services/backup/flags.aconfig @@ -7,4 +7,12 @@ flag { "restore for apps that have been launched." bug: "308401499" is_fixed_read_only: true +} + +flag { + name: "enable_max_size_writes_to_pipes" + namespace: "onboarding" + description: "Enables the write buffer to pipes to be of maximum size." + bug: "265976737" + is_fixed_read_only: true }
\ No newline at end of file diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index 6aed9aa15860..cca166b0939c 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -40,8 +40,8 @@ import android.util.Slog; import com.android.server.EventLogTags; import com.android.server.backup.BackupAgentTimeoutParameters; -import com.android.server.backup.BackupAndRestoreFeatureFlags; import com.android.server.backup.BackupRestoreTask; +import com.android.server.backup.Flags; import com.android.server.backup.FullBackupJob; import com.android.server.backup.OperationStorage; import com.android.server.backup.OperationStorage.OpState; @@ -390,8 +390,11 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba // Set up to send data to the transport final int N = mPackages.size(); - final int chunkSizeInBytes = - BackupAndRestoreFeatureFlags.getFullBackupWriteToTransportBufferSizeBytes(); + int chunkSizeInBytes = 8 * 1024; // 8KB + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + chunkSizeInBytes = 64 * 1024; // 64KB + } final byte[] buffer = new byte[chunkSizeInBytes]; for (int i = 0; i < N; i++) { mBackupRunner = null; diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index ff72476d4bf1..2c9eb51972af 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -29,7 +29,6 @@ import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; import android.app.backup.BackupAgent; import android.app.backup.BackupAnnotations; -import android.app.backup.BackupManager; import android.app.backup.FullBackup; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IFullBackupRestoreObserver; @@ -51,6 +50,7 @@ import com.android.server.LocalServices; import com.android.server.backup.BackupAgentTimeoutParameters; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; +import com.android.server.backup.Flags; import com.android.server.backup.KeyValueAdbRestoreEngine; import com.android.server.backup.OperationStorage; import com.android.server.backup.OperationStorage.OpType; @@ -157,13 +157,19 @@ public class FullRestoreEngine extends RestoreEngine { mMonitor = monitor; mOnlyPackage = onlyPackage; mAllowApks = allowApks; - mBuffer = new byte[32 * 1024]; mAgentTimeoutParameters = Objects.requireNonNull( backupManagerService.getAgentTimeoutParameters(), "Timeout parameters cannot be null"); mIsAdbRestore = isAdbRestore; mUserId = backupManagerService.getUserId(); mBackupEligibilityRules = backupEligibilityRules; + + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + mBuffer = new byte[64 * 1024]; // 64KB + } else { + mBuffer = new byte[32 * 1024]; + } } @VisibleForTesting diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 316a16d9934c..2fbc3cd24d65 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -968,7 +968,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { throws Exception { Set<String> excludedKeysForPackage = getExcludedKeysForPackage(packageName); - byte[] buffer = new byte[8192]; // will grow when needed + int bufferSize = 8192; // 8KB + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + bufferSize = 64 * 1024; // 64KB + } + byte[] buffer = new byte[bufferSize]; // will grow when needed while (in.readNextHeader()) { final String key = in.getKey(); final int size = in.getDataSize(); @@ -1116,7 +1121,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { ParcelFileDescriptor tReadEnd = mTransportPipes[0]; ParcelFileDescriptor tWriteEnd = mTransportPipes[1]; - int bufferSize = 32 * 1024; + int bufferSize = 32 * 1024; // 32KB + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + bufferSize = 64 * 1024; // 64KB + } byte[] buffer = new byte[bufferSize]; FileOutputStream engineOut = new FileOutputStream(eWriteEnd.getFileDescriptor()); FileInputStream transportIn = new FileInputStream(tReadEnd.getFileDescriptor()); diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java index 1c0cd87cec6f..843354e719bb 100644 --- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java @@ -21,7 +21,7 @@ import static com.android.server.backup.BackupManagerService.TAG; import android.os.ParcelFileDescriptor; import android.util.Slog; -import com.android.server.backup.BackupAndRestoreFeatureFlags; +import com.android.server.backup.Flags; import java.io.DataInputStream; import java.io.EOFException; @@ -46,8 +46,11 @@ public class FullBackupUtils { // We do not take close() responsibility for the pipe FD FileInputStream raw = new FileInputStream(inPipe.getFileDescriptor()); DataInputStream in = new DataInputStream(raw); - final int chunkSizeInBytes = - BackupAndRestoreFeatureFlags.getFullBackupUtilsRouteBufferSizeBytes(); + int chunkSizeInBytes = 32 * 1024; // 32KB + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + chunkSizeInBytes = 64 * 1024; // 64KB + } byte[] buffer = new byte[chunkSizeInBytes]; int chunkTotal; while ((chunkTotal = in.readInt()) > 0) { diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java index 0accb9fadd04..5a8533a2daee 100644 --- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java +++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java @@ -40,6 +40,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.server.LocalServices; import com.android.server.backup.FileMetadata; +import com.android.server.backup.Flags; import com.android.server.backup.restore.RestoreDeleteObserver; import com.android.server.backup.restore.RestorePolicy; @@ -93,7 +94,12 @@ public class RestoreUtils { try (Session session = installer.openSession(sessionId)) { try (OutputStream apkStream = session.openWrite(info.packageName, 0, info.size)) { - byte[] buffer = new byte[32 * 1024]; + int bufferSize = 32 * 1024; // 32KB + if (Flags.enableMaxSizeWritesToPipes()) { + // Linux pipe capacity (buffer size) is 16 pages where each page is 4KB + bufferSize = 64 * 1024; // 64KB + } + byte[] buffer = new byte[bufferSize]; long size = info.size; while (size > 0) { long toRead = (buffer.length < size) ? buffer.length : size; diff --git a/services/backup/lint-baseline.xml b/services/backup/lint-baseline.xml index 93c9390feb9c..46de2cdd7a47 100644 --- a/services/backup/lint-baseline.xml +++ b/services/backup/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NonUserGetterCalled" @@ -36,4 +36,4 @@ line="207"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java index 4b3772a7a54d..d0eb59d83f5a 100644 --- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java @@ -22,6 +22,7 @@ import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR; import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR; import static android.content.ComponentName.createRelative; +import static android.content.pm.PackageManager.FEATURE_WATCH; import static com.android.server.companion.CompanionDeviceManagerService.DEBUG; import static com.android.server.companion.MetricUtils.logCreateAssociation; @@ -169,16 +170,29 @@ class AssociationRequestsProcessor { enforcePermissionsForAssociation(mContext, request, packageUid); enforceUsesCompanionDeviceFeature(mContext, userId, packageName); - // 2. Check if association can be created without launching UI (i.e. CDM needs NEITHER + // 2a. Check if association can be created without launching UI (i.e. CDM needs NEITHER // to perform discovery NOR to collect user consent). if (request.isSelfManaged() && !request.isForceConfirmation() && !willAddRoleHolder(request, packageName, userId)) { - // 2a. Create association right away. + // 2a.1. Create association right away. createAssociationAndNotifyApplication(request, packageName, userId, /* macAddress */ null, callback, /* resultReceiver */ null); return; } + // 2a.2. Report an error if a 3p app tries to create a non-self-managed association and + // launch UI on watch. + if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) { + String errorMessage = "3p apps are not allowed to create associations on watch."; + Slog.e(TAG, errorMessage); + try { + callback.onFailure(errorMessage); + } catch (RemoteException e) { + // ignored + } + return; + } + // 2b. Build a PendingIntent for launching the confirmation UI, and send it back to the app: // 2b.1. Populate the request with required info. diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 4e471f5b0bc9..260b21f109d0 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -21,6 +21,7 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE; import static android.content.ComponentName.createRelative; +import static android.content.pm.PackageManager.FEATURE_WATCH; import static com.android.server.companion.Utils.prepareForIpc; @@ -40,6 +41,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManagerInternal; import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -306,6 +308,13 @@ public class SystemDataTransferProcessor { } private void onReceivePermissionRestore(byte[] message) { + // TODO: Disable Permissions Sync for non-watch devices until we figure out a better UX + // model + if (!Build.isDebuggable() && !mContext.getPackageManager().hasSystemFeature( + FEATURE_WATCH)) { + Slog.e(LOG_TAG, "Permissions restore is only available on watch."); + return; + } Slog.i(LOG_TAG, "Applying permissions."); // Start applying permissions UserHandle user = mContext.getUser(); diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java index 720687ef20cc..0e66fbc020a1 100644 --- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java +++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java @@ -23,12 +23,12 @@ import android.content.Context; import android.os.Build; import android.util.Slog; -import com.google.security.cryptauth.lib.securegcm.BadHandleException; -import com.google.security.cryptauth.lib.securegcm.CryptoException; -import com.google.security.cryptauth.lib.securegcm.D2DConnectionContextV1; -import com.google.security.cryptauth.lib.securegcm.D2DHandshakeContext; -import com.google.security.cryptauth.lib.securegcm.D2DHandshakeContext.Role; -import com.google.security.cryptauth.lib.securegcm.HandshakeException; +import com.google.security.cryptauth.lib.securegcm.ukey2.BadHandleException; +import com.google.security.cryptauth.lib.securegcm.ukey2.CryptoException; +import com.google.security.cryptauth.lib.securegcm.ukey2.D2DConnectionContextV1; +import com.google.security.cryptauth.lib.securegcm.ukey2.D2DHandshakeContext; +import com.google.security.cryptauth.lib.securegcm.ukey2.D2DHandshakeContext.Role; +import com.google.security.cryptauth.lib.securegcm.ukey2.HandshakeException; import libcore.io.IoUtils; import libcore.io.Streams; diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java index 62c670317f5f..3e45626d9799 100644 --- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java +++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java @@ -125,7 +125,7 @@ public class CompanionTransportManager { * Send a message to remote devices through the transports */ public void sendMessage(int message, byte[] data, int[] associationIds) { - Slog.i(TAG, "Sending message 0x" + Integer.toHexString(message) + Slog.d(TAG, "Sending message 0x" + Integer.toHexString(message) + " data length " + data.length); synchronized (mTransports) { for (int i = 0; i < associationIds.length; i++) { diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java index 22b18ac9653b..8a5774e55ce2 100644 --- a/services/companion/java/com/android/server/companion/transport/Transport.java +++ b/services/companion/java/com/android/server/companion/transport/Transport.java @@ -284,7 +284,7 @@ public abstract class Transport { if (mListeners.containsKey(message)) { try { mListeners.get(message).onMessageReceived(getAssociationId(), data); - Slog.i(TAG, "Message 0x" + Integer.toHexString(message) + Slog.d(TAG, "Message 0x" + Integer.toHexString(message) + " is received from associationId " + mAssociationId + ", sending data length " + data.length + " to the listener."); } catch (RemoteException ignored) { diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java index 1f89e57b90d7..d1274d49a14d 100644 --- a/services/companion/java/com/android/server/companion/virtual/InputController.java +++ b/services/companion/java/com/android/server/companion/virtual/InputController.java @@ -245,8 +245,8 @@ class InputController { mInputManagerInternal.setPointerIconVisible(visible, displayId); } - void setPointerAcceleration(float pointerAcceleration, int displayId) { - mInputManagerInternal.setPointerAcceleration(pointerAcceleration, displayId); + void setMousePointerAccelerationEnabled(boolean enabled, int displayId) { + mInputManagerInternal.setMousePointerAccelerationEnabled(enabled, displayId); } void setDisplayEligibilityForPointerCapture(boolean isEligible, int displayId) { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 58aa2c303345..44c3a8d7537f 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -1110,7 +1110,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub final long token = Binder.clearCallingIdentity(); try { mInputController.setShowPointerIcon(showPointer, displayId); - mInputController.setPointerAcceleration(1f, displayId); + mInputController.setMousePointerAccelerationEnabled(false, displayId); mInputController.setDisplayEligibilityForPointerCapture(/* isEligible= */ false, displayId); // WM throws a SecurityException if the display is untrusted. diff --git a/services/companion/lint-baseline.xml b/services/companion/lint-baseline.xml index 03eae3901e51..020126f75ea0 100644 --- a/services/companion/lint-baseline.xml +++ b/services/companion/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NonUserGetterCalled" @@ -12,4 +12,4 @@ column="14"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/core/Android.bp b/services/core/Android.bp index a3fc3bf5ec72..a6ed498e93db 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -234,9 +234,6 @@ java_genrule { java_library { name: "services.core", static_libs: ["services.core.priorityboosted"], - lint: { - baseline_filename: "lint-baseline.xml", - }, } java_library_host { diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 9eb35fde50fb..eb6fdd72f2c3 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -101,6 +101,7 @@ import com.android.internal.telephony.IOnSubscriptionsChangedListener; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.TelephonyPermissions; +import com.android.internal.telephony.flags.Flags; import com.android.internal.telephony.util.TelephonyUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -2679,6 +2680,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyEmergencyNumberList()")) { return; } + if (Flags.enforceTelephonyFeatureMappingForPublicApis()) { + if (!mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELEPHONY_CALLING)) { + // TelephonyManager.getEmergencyNumberList() throws an exception if + // FEATURE_TELEPHONY_CALLING is not defined. + return; + } + } synchronized (mRecords) { if (validatePhoneId(phoneId)) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 85abf87b4b2e..130a7333959d 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -3152,6 +3152,7 @@ public class AccountManagerService new AccountAuthenticatorResponse(this), authTokenType, true); + mCanStartAccountManagerActivity = true; Bundle bundle = new Bundle(); bundle.putParcelable(AccountManager.KEY_INTENT, intent); onResult(bundle); @@ -4933,6 +4934,7 @@ public class AccountManagerService IAccountAuthenticator mAuthenticator = null; private final boolean mStripAuthTokenFromResult; + protected boolean mCanStartAccountManagerActivity = false; protected final UserAccounts mAccounts; public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType, @@ -5068,9 +5070,13 @@ public class AccountManagerService private boolean isExportedSystemActivity(ActivityInfo activityInfo) { String className = activityInfo.name; - return "android".equals(activityInfo.packageName) && - (GrantCredentialsPermissionActivity.class.getName().equals(className) - || CantAddAccountActivity.class.getName().equals(className)); + if (!"android".equals(activityInfo.packageName)) { + return false; + + } + return (mCanStartAccountManagerActivity + && GrantCredentialsPermissionActivity.class.getName().equals(className)) + || CantAddAccountActivity.class.getName().equals(className); } private void close() { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 02f4485d5b40..0cff8b7e88ed 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4464,6 +4464,12 @@ public final class ActiveServices { } } if (userId > 0) { + if (mAm.isSystemUserOnly(sInfo.flags)) { + Slog.w(TAG_SERVICE, service + " is only available for the SYSTEM user," + + " calling userId is: " + userId); + return null; + } + if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo, sInfo.name, sInfo.flags) && mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) { @@ -5453,7 +5459,7 @@ public final class ActiveServices { // Force an immediate oomAdjUpdate, so the client app could be in the correct process state // before doing any service related transactions mAm.enqueueOomAdjTargetLocked(app); - mAm.updateOomAdjLocked(app, OOM_ADJ_REASON_START_SERVICE); + mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); boolean created = false; try { diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 8ad60e6a0782..72e62c37106d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -243,7 +243,7 @@ final class ActivityManagerConstants extends ContentObserver { /** * The default value to {@link #KEY_ENABLE_NEW_OOMADJ}. */ - private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = Flags.oomadjusterCorrectnessRewrite(); + private static final boolean DEFAULT_ENABLE_NEW_OOM_ADJ = false; /** * Same as {@link TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index fddb5707b78e..e583a6cd6b1f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13747,6 +13747,11 @@ public class ActivityManagerService extends IActivityManager.Stub return result; } + boolean isSystemUserOnly(int flags) { + return android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders() + && (flags & ServiceInfo.FLAG_SYSTEM_USER_ONLY) != 0; + } + /** * Checks to see if the caller is in the same app as the singleton * component, or the component is in a special app. It allows special apps @@ -20144,8 +20149,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Returns the {@link BatteryStatsService} instance */ public BatteryStatsService getBatteryStatsService() { - return new BatteryStatsService(mContext, SystemServiceManager.ensureSystemDir(), - BackgroundThread.get().getHandler()); + return new BatteryStatsService(mContext, SystemServiceManager.ensureSystemDir()); } /** diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java index e0a224629174..9fc0bf920969 100644 --- a/services/core/java/com/android/server/am/AnrHelper.java +++ b/services/core/java/com/android/server/am/AnrHelper.java @@ -63,6 +63,11 @@ class AnrHelper { private static final long CONSECUTIVE_ANR_TIME_MS = TimeUnit.MINUTES.toMillis(2); /** + * Time to wait before taking dumps for other processes to reduce load at boot time. + */ + private static final long SELF_ONLY_AFTER_BOOT_MS = TimeUnit.MINUTES.toMillis(10); + + /** * The keep alive time for the threads in the helper threadpool executor */ private static final int DEFAULT_THREAD_KEEP_ALIVE_SECOND = 10; @@ -231,7 +236,8 @@ class AnrHelper { // If there are many ANR at the same time, the latency may be larger. // If the latency is too large, the stack trace might not be meaningful. final long reportLatency = startTime - r.mTimestamp; - final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS; + final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS + || startTime < SELF_ONLY_AFTER_BOOT_MS; r.appNotResponding(onlyDumpSelf); final long endTime = SystemClock.uptimeMillis(); Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in " diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index eea93374886d..c96c2ff4f2eb 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -381,8 +381,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } }; - BatteryStatsService(Context context, File systemDir, Handler handler) { - // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. + BatteryStatsService(Context context, File systemDir) { mContext = context; mUserManagerUserInfoProvider = new BatteryStatsImpl.UserInfoProvider() { private UserManagerInternal umi; @@ -416,7 +415,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub .build(); mPowerStatsUidResolver = new PowerStatsUidResolver(); mStats = new BatteryStatsImpl(mBatteryStatsConfig, Clock.SYSTEM_CLOCK, mMonotonicClock, - systemDir, handler, this, this, mUserManagerUserInfoProvider, mPowerProfile, + systemDir, mHandler, this, this, mUserManagerUserInfoProvider, mPowerProfile, mCpuScalingPolicies, mPowerStatsUidResolver); mWorker = new BatteryExternalStatsWorker(context, mStats); mStats.setExternalStatsSyncLocked(mWorker); @@ -477,7 +476,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub */ public static BatteryStatsService create(Context context, File systemDir, Handler handler, BatteryStatsImpl.BatteryCallback callback) { - BatteryStatsService service = new BatteryStatsService(context, systemDir, handler); + BatteryStatsService service = new BatteryStatsService(context, systemDir); service.mStats.setCallback(callback); synchronized (service.mStats) { service.mStats.readLocked(); diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java index 095d907d7df6..30f21a65b5b1 100644 --- a/services/core/java/com/android/server/am/ContentProviderHelper.java +++ b/services/core/java/com/android/server/am/ContentProviderHelper.java @@ -1249,9 +1249,9 @@ public class ContentProviderHelper { ProviderInfo cpi = providers.get(i); boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags); - if (singleton && app.userId != UserHandle.USER_SYSTEM) { - // This is a singleton provider, but a user besides the - // default user is asking to initialize a process it runs + if (isSingletonOrSystemUserOnly(cpi) && app.userId != UserHandle.USER_SYSTEM) { + // This is a singleton or a SYSTEM user only provider, but a user besides the + // SYSTEM user is asking to initialize a process it runs // in... well, no, it doesn't actually run in this process, // it runs in the process of the default user. Get rid of it. providers.remove(i); @@ -1398,8 +1398,7 @@ public class ContentProviderHelper { final boolean processMatch = Objects.equals(pi.processName, app.processName) || pi.multiprocess; - final boolean userMatch = !mService.isSingleton( - pi.processName, pi.applicationInfo, pi.name, pi.flags) + final boolean userMatch = !isSingletonOrSystemUserOnly(pi) || app.userId == UserHandle.USER_SYSTEM; final boolean isInstantApp = pi.applicationInfo.isInstantApp(); final boolean splitInstalled = pi.splitName == null @@ -1985,4 +1984,13 @@ public class ContentProviderHelper { return isAuthRedirected; } } + + /** + * Returns true if Provider is either singleUser or systemUserOnly provider. + */ + private boolean isSingletonOrSystemUserOnly(ProviderInfo pi) { + return (android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders() + && mService.isSystemUserOnly(pi.flags)) + || mService.isSingleton(pi.processName, pi.applicationInfo, pi.name, pi.flags); + } } diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java index 9f31f375dafe..5f12ce1e4163 100644 --- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java +++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java @@ -73,7 +73,8 @@ public class AmbientContextManagerService extends private static final Set<Integer> DEFAULT_EVENT_SET = Sets.newHashSet( AmbientContextEvent.EVENT_COUGH, AmbientContextEvent.EVENT_SNORE, - AmbientContextEvent.EVENT_BACK_DOUBLE_TAP); + AmbientContextEvent.EVENT_BACK_DOUBLE_TAP, + AmbientContextEvent.EVENT_HEART_RATE); /** Default value in absence of {@link DeviceConfig} override. */ private static final boolean DEFAULT_SERVICE_ENABLED = true; diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index dada72eb51d9..f80228afa52d 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -1812,6 +1812,7 @@ public class AudioDeviceBroker { "msg: MSG_L_SET_BT_ACTIVE_DEVICE " + "received with null profile proxy: " + btInfo)).printLog(TAG)); + sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, 0 /*delay*/); return; } @AudioSystem.AudioFormatNativeEnumForBtCodec final int codec = diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index e05824a5f1ab..bf20ae3b516d 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -1992,7 +1992,7 @@ public class AudioDeviceInventory { // TODO: return; } else { AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent( - "A2DP source device addr=" + Utils.anonymizeBluetoothAddress(address) + "A2DP sink device addr=" + Utils.anonymizeBluetoothAddress(address) + " now available").printLog(TAG)); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 91d533c73b5d..4cbee2b89bb2 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -8835,6 +8835,8 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { oldIndex = getIndex(device); index = getValidIndex(index, hasModifyAudioSettings); + // for STREAM_SYSTEM_ENFORCED, do not sync aliased streams on the enforced index + int aliasIndex = index; if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) { index = mIndexMax; } @@ -8853,7 +8855,8 @@ public class AudioService extends IAudioService.Stub if (streamType != mStreamType && mStreamVolumeAlias[streamType] == mStreamType && (changed || !aliasStreamState.hasIndexForDevice(device))) { - final int scaledIndex = rescaleIndex(index, mStreamType, streamType); + final int scaledIndex = + rescaleIndex(aliasIndex, mStreamType, streamType); aliasStreamState.setIndex(scaledIndex, device, caller, hasModifyAudioSettings); if (isCurrentDevice) { @@ -9375,6 +9378,14 @@ public class AudioService extends IAudioService.Stub if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) { return; } + + // Persisting STREAM_SYSTEM_ENFORCED index is not needed as its alias (STREAM_RING) + // is persisted. This can also be problematic when the enforcement is active as it will + // override current SYSTEM_RING persisted value given they share the same settings name + // (due to aliasing). + if (streamState.mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) { + return; + } if (streamState.hasValidSettingsName()) { mSettings.putSystemIntForUser(mContentResolver, streamState.getSettingNameForDevice(device), diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index a818c30c2e28..f51043dc1cdc 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -634,16 +634,17 @@ public class BtHelper { return; } List<BluetoothDevice> activeDevices = adapter.getActiveDevices(profile); - if (activeDevices.isEmpty() || activeDevices.get(0) == null) { - return; + BluetoothProfileConnectionInfo bpci = new BluetoothProfileConnectionInfo(profile); + for (BluetoothDevice device : activeDevices) { + if (device == null) { + continue; + } + AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData( + device, null, bpci, "mBluetoothProfileServiceListener"); + AudioDeviceBroker.BtDeviceInfo info = mDeviceBroker.createBtDeviceInfo( + data, device, BluetoothProfile.STATE_CONNECTED); + mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */); } - AudioDeviceBroker.BtDeviceChangedData data = new AudioDeviceBroker.BtDeviceChangedData( - activeDevices.get(0), null, new BluetoothProfileConnectionInfo(profile), - "mBluetoothProfileServiceListener"); - AudioDeviceBroker.BtDeviceInfo info = - mDeviceBroker.createBtDeviceInfo(data, activeDevices.get(0), - BluetoothProfile.STATE_CONNECTED); - mDeviceBroker.postBluetoothActiveDevice(info, 0 /* delay */); } // @GuardedBy("mDeviceBroker.mSetModeLock") @@ -678,8 +679,11 @@ public class BtHelper { if (adapter != null) { List<BluetoothDevice> activeDevices = adapter.getActiveDevices(BluetoothProfile.HEADSET); - if (activeDevices.size() > 0 && activeDevices.get(0) != null) { - onSetBtScoActiveDevice(activeDevices.get(0)); + for (BluetoothDevice device : activeDevices) { + if (device == null) { + continue; + } + onSetBtScoActiveDevice(device); } } else { Log.e(TAG, "onHeadsetProfileConnected: Null BluetoothAdapter"); diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index c2bc1e4f6be2..a30cdc47a461 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -62,6 +62,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -147,6 +148,15 @@ public class SoundDoseHelper { private static final int SAFE_MEDIA_VOLUME_UNINITIALIZED = -1; + // see {@link #recordToPersistedString(SoundDoseRecord)} + // this is computed conservatively to accommodate the legacy persisting of SoundDoseRecords in + // which we materialized more decimal values. + // TODO: adjust value after soaking in + private static final int MAX_RECORDS_STRING_LENGTH = 50; + private static final int MAX_SETTINGS_LENGTH = 32768; + private static final int MAX_NUMBER_OF_CACHED_RECORDS = + MAX_SETTINGS_LENGTH / MAX_RECORDS_STRING_LENGTH; + private final EventLogger mLogger = new EventLogger(AudioService.LOG_NB_EVENTS_SOUND_DOSE, "CSD updates"); @@ -923,7 +933,7 @@ public class SoundDoseHelper { Log.v(TAG, "Initializing sound dose"); try { - if (mCachedAudioDeviceCategories.size() > 0) { + if (!mCachedAudioDeviceCategories.isEmpty()) { soundDose.initCachedAudioDeviceCategories(mCachedAudioDeviceCategories.toArray( new ISoundDose.AudioDeviceCategory[0])); mCachedAudioDeviceCategories.clear(); @@ -957,6 +967,7 @@ public class SoundDoseHelper { mGlobalTimeOffsetInSecs); if (records != null) { mDoseRecords.addAll(records); + sanitizeDoseRecords_l(); } } } @@ -1176,17 +1187,35 @@ public class SoundDoseHelper { && r.duration == record.duration)) { Log.w(TAG, "Could not find cached record to remove: " + record); } - } else { + } else if (record.value > 0) { mDoseRecords.add(record); } } + sanitizeDoseRecords_l(); + mAudioHandler.sendMessageAtTime(mAudioHandler.obtainMessage(MSG_PERSIST_CSD_VALUES, /* arg1= */0, /* arg2= */0, /* obj= */null), /* delay= */0); mLogger.enqueue(SoundDoseEvent.getDoseUpdateEvent(currentCsd, totalDuration)); } + @GuardedBy("mCsdStateLock") + private void sanitizeDoseRecords_l() { + if (mDoseRecords.size() > MAX_NUMBER_OF_CACHED_RECORDS) { + int nrToRemove = MAX_NUMBER_OF_CACHED_RECORDS - mDoseRecords.size(); + Log.w(TAG, + "Removing " + nrToRemove + " records from the total of " + mDoseRecords.size()); + // Remove older elements to fit into persisted settings max length + Iterator<SoundDoseRecord> recordIterator = mDoseRecords.iterator(); + while (recordIterator.hasNext() && nrToRemove > 0) { + recordIterator.next(); + recordIterator.remove(); + --nrToRemove; + } + } + } + @SuppressWarnings("GuardedBy") // avoid limitation with intra-procedural analysis of lambdas private void onPersistSoundDoseRecords() { synchronized (mCsdStateLock) { @@ -1213,8 +1242,8 @@ public class SoundDoseHelper { long globalTimeOffsetInSecs) { return convertToGlobalTime(record.timestamp, globalTimeOffsetInSecs) + PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.duration - + PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.value - + PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.averageMel; + + PERSIST_CSD_RECORD_FIELD_SEPARATOR + String.format("%.3f", record.value) + + PERSIST_CSD_RECORD_FIELD_SEPARATOR + String.format("%.3f", record.averageMel); } private static long convertToGlobalTime(long bootTimeInSecs, long globalTimeOffsetInSecs) { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index fbac924be283..9cf9119aff82 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -3390,17 +3390,10 @@ public final class DisplayManagerService extends SystemService { // with the corresponding displaydevice. HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); - if (mConfigParameterProvider.isNewPowerControllerFeatureEnabled()) { - displayPowerController = new DisplayPowerController2( - mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler, - mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, - () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted, mFlags); - } else { - displayPowerController = new DisplayPowerController( - mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler, - mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, - () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted, mFlags); - } + displayPowerController = new DisplayPowerController( + mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler, + mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting, + () -> handleBrightnessChange(display), hbmMetadata, mBootCompleted, mFlags); mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController); return displayPowerController; } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 734381b1ddb0..087cacf9a570 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,11 +17,12 @@ package com.android.server.display; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; +import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessPresetToString; import android.animation.Animator; import android.animation.ObjectAnimator; -import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; @@ -31,8 +32,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; @@ -45,6 +44,7 @@ import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; import android.metrics.LogMaker; import android.net.Uri; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.IBinder; import android.os.Looper; import android.os.Message; @@ -56,12 +56,12 @@ import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.util.FloatProperty; +import android.util.IndentingPrintWriter; import android.util.MathUtils; import android.util.MutableFloat; import android.util.MutableInt; import android.util.Slog; import android.util.SparseArray; -import android.util.TimeUtils; import android.view.Display; import com.android.internal.R; @@ -78,10 +78,15 @@ import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.brightness.BrightnessUtils; +import com.android.server.display.brightness.DisplayBrightnessController; +import com.android.server.display.brightness.clamper.BrightnessClamperController; +import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal; import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; import com.android.server.display.feature.DisplayManagerFlags; import com.android.server.display.layout.Layout; +import com.android.server.display.state.DisplayStateController; import com.android.server.display.utils.DebugUtils; import com.android.server.display.utils.SensorUtils; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; @@ -119,12 +124,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked"; private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked"; - private static final String TAG = "DisplayPowerController"; + private static final String TAG = "DisplayPowerController2"; // To enable these logs, run: - // 'adb shell setprop persist.log.tag.DisplayPowerController DEBUG && adb reboot' + // 'adb shell setprop persist.log.tag.DisplayPowerController2 DEBUG && adb reboot' private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); - - private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false; + private static final String SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME = + "Screen on blocked by displayoffload"; // If true, uses the color fade on animation. // We might want to turn this off if we cannot get a guarantee that the screen @@ -138,36 +143,28 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400; private static final int MSG_UPDATE_POWER_STATE = 1; - private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2; - private static final int MSG_SCREEN_ON_UNBLOCKED = 3; - private static final int MSG_SCREEN_OFF_UNBLOCKED = 4; - private static final int MSG_CONFIGURE_BRIGHTNESS = 5; - private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 6; - private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 7; - private static final int MSG_IGNORE_PROXIMITY = 8; - private static final int MSG_STOP = 9; - private static final int MSG_UPDATE_BRIGHTNESS = 10; - private static final int MSG_UPDATE_RBC = 11; - private static final int MSG_BRIGHTNESS_RAMP_DONE = 12; - private static final int MSG_STATSD_HBM_BRIGHTNESS = 13; - private static final int MSG_SWITCH_USER = 14; - private static final int MSG_BOOT_COMPLETED = 15; - private static final int MSG_SET_DWBC_STRONG_MODE = 16; - private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 17; - private static final int MSG_SET_DWBC_LOGGING_ENABLED = 18; - - private static final int PROXIMITY_UNKNOWN = -1; - private static final int PROXIMITY_NEGATIVE = 0; - private static final int PROXIMITY_POSITIVE = 1; - - // Proximity sensor debounce delay in milliseconds for positive or negative transitions. - private static final int PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY = 0; - private static final int PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY = 250; + private static final int MSG_SCREEN_ON_UNBLOCKED = 2; + private static final int MSG_SCREEN_OFF_UNBLOCKED = 3; + private static final int MSG_CONFIGURE_BRIGHTNESS = 4; + private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 5; + private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 6; + private static final int MSG_STOP = 7; + private static final int MSG_UPDATE_BRIGHTNESS = 8; + private static final int MSG_UPDATE_RBC = 9; + private static final int MSG_BRIGHTNESS_RAMP_DONE = 10; + private static final int MSG_STATSD_HBM_BRIGHTNESS = 11; + private static final int MSG_SWITCH_USER = 12; + private static final int MSG_BOOT_COMPLETED = 13; + private static final int MSG_SET_DWBC_STRONG_MODE = 14; + private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; + private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; + private static final int MSG_SET_BRIGHTNESS_FROM_OFFLOAD = 17; + private static final int MSG_OFFLOADING_SCREEN_ON_UNBLOCKED = 18; + + private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500; - // Trigger proximity if distance is less than 5 cm. - private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f; // State machine constants for tracking initial brightness ramp skipping when enabled. private static final int RAMP_STATE_SKIP_NONE = 0; @@ -181,6 +178,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3; private static final int RINGBUFFER_MAX = 100; + private static final int RINGBUFFER_RBC_MAX = 20; private static final float[] BRIGHTNESS_RANGE_BOUNDARIES = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, @@ -236,10 +234,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Our handler. private final DisplayControllerHandler mHandler; - // Asynchronous callbacks into the power manager service. - // Only invoked from the handler thread while no locks are held. - private final DisplayPowerCallbacks mCallbacks; - // Battery stats. @Nullable private final IBatteryStats mBatteryStats; @@ -253,10 +247,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The display blanker. private final DisplayBlanker mBlanker; - // The LogicalDisplay tied to this DisplayPowerController. + // The LogicalDisplay tied to this DisplayPowerController2. private final LogicalDisplay mLogicalDisplay; - // The ID of the LogicalDisplay tied to this DisplayPowerController. + // The ID of the LogicalDisplay tied to this DisplayPowerController2. private final int mDisplayId; // The ID of the display which this display follows for brightness purposes. @@ -272,34 +266,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Tracker for brightness settings changes. private final SettingsObserver mSettingsObserver; - // The proximity sensor, or null if not available or needed. - private Sensor mProximitySensor; - // The doze screen brightness. private final float mScreenBrightnessDozeConfig; - // The dim screen brightness. - private final float mScreenBrightnessDimConfig; - - // The minimum dim amount to use if the screen brightness is already below - // mScreenBrightnessDimConfig. - private final float mScreenBrightnessMinimumDimAmount; - - private final float mScreenBrightnessDefault; - // True if auto-brightness should be used. private boolean mUseSoftwareAutoBrightnessConfig; - // True if should use light sensor to automatically determine doze screen brightness. - private final boolean mAllowAutoBrightnessWhileDozingConfig; - - // True if we want to persist the brightness value in nits even if the underlying display - // device changes. - private final boolean mPersistBrightnessNitsForDefaultDisplay; - - // True if the brightness config has changed and the short-term model needs to be reset - private boolean mShouldResetShortTermModel; - // Whether or not the color fade on screen on / off is enabled. private final boolean mColorFadeEnabled; @@ -340,10 +312,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @GuardedBy("mLock") private DisplayPowerRequest mPendingRequestLocked; - // True if a request has been made to wait for the proximity sensor to go negative. - @GuardedBy("mLock") - private boolean mPendingWaitForNegativeProximityLocked; - // True if the pending power request or wait for negative proximity flag // has been changed since the last update occurred. @GuardedBy("mLock") @@ -370,67 +338,36 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Must only be accessed on the handler thread. private DisplayPowerState mPowerState; - // True if the device should wait for negative proximity sensor before - // waking up the screen. This is set to false as soon as a negative - // proximity sensor measurement is observed or when the device is forced to - // go to sleep by the user. While true, the screen remains off. - private boolean mWaitingForNegativeProximity; - - // True if the device should not take into account the proximity sensor - // until either the proximity sensor state changes, or there is no longer a - // request to listen to proximity sensor. - private boolean mIgnoreProximityUntilChanged; - - // The actual proximity sensor threshold value. - private float mProximityThreshold; - // Set to true if the proximity sensor listener has been registered - // with the sensor manager. - private boolean mProximitySensorEnabled; - - // The debounced proximity sensor state. - private int mProximity = PROXIMITY_UNKNOWN; - - // The raw non-debounced proximity sensor state. - private int mPendingProximity = PROXIMITY_UNKNOWN; - private long mPendingProximityDebounceTime = -1; // -1 if fully debounced - - // True if the screen was turned off because of the proximity sensor. - // When the screen turns on again, we report user activity to the power manager. - private boolean mScreenOffBecauseOfProximity; // The currently active screen on unblocker. This field is non-null whenever // we are waiting for a callback to release it and unblock the screen. private ScreenOnUnblocker mPendingScreenOnUnblocker; private ScreenOffUnblocker mPendingScreenOffUnblocker; + private Runnable mPendingScreenOnUnblockerByDisplayOffload; // True if we were in the process of turning off the screen. // This allows us to recover more gracefully from situations where we abort // turning off the screen. private boolean mPendingScreenOff; - // True if we have unfinished business and are holding a suspend blocker. - private boolean mUnfinishedBusiness; - // The elapsed real time when the screen on was blocked. private long mScreenOnBlockStartRealTime; private long mScreenOffBlockStartRealTime; + private long mScreenOnBlockByDisplayOffloadStartRealTime; // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_* fields. private int mReportedScreenStateToPolicy = REPORTED_TO_POLICY_UNREPORTED; + // Used to deduplicate the displayoffload blocking screen on logic. One block per turning on. + // This value is reset when screen on is reported or the blocking is cancelled. + private boolean mScreenTurningOnWasBlockedByDisplayOffload; + // If the last recorded screen state was dozing or not. private boolean mDozing; - // Remembers whether certain kinds of brightness adjustments - // were recently applied so that we can decide how to transition. - private boolean mAppliedAutoBrightness; private boolean mAppliedDimming; - private boolean mAppliedLowPower; - private boolean mAppliedScreenBrightnessOverride; - private boolean mAppliedTemporaryBrightness; - private boolean mAppliedTemporaryAutoBrightnessAdjustment; - private boolean mAppliedBrightnessBoost; + private boolean mAppliedThrottling; // Reason for which the brightness was last changed. See {@link BrightnessReason} for more @@ -456,7 +393,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private final boolean mSkipScreenOnBrightnessRamp; // Display white balance components. - // Critical methods must be called on DPC handler thread. + // Critical methods must be called on DPC2 handler thread. @Nullable private final DisplayWhiteBalanceSettings mDisplayWhiteBalanceSettings; @Nullable @@ -468,21 +405,39 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private final BrightnessRangeController mBrightnessRangeController; - @Nullable - private final HighBrightnessModeMetadata mHighBrightnessModeMetadata; - private final BrightnessThrottler mBrightnessThrottler; - private final BrightnessSetting mBrightnessSetting; + private final BrightnessClamperController mBrightnessClamperController; private final Runnable mOnBrightnessChangeRunnable; private final BrightnessEvent mLastBrightnessEvent; private final BrightnessEvent mTempBrightnessEvent; + private final DisplayBrightnessController mDisplayBrightnessController; + // Keeps a record of brightness changes for dumpsys. private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer; + // Keeps a record of rbc changes for dumpsys. + private final RingBuffer<BrightnessEvent> mRbcEventRingBuffer = + new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_RBC_MAX); + + // Controls and tracks all the wakelocks that are acquired/released by the system. Also acts as + // a medium of communication between this class and the PowerManagerService. + private final WakelockController mWakelockController; + + // Tracks and manages the proximity state of the associated display. + private final DisplayPowerProximityStateController mDisplayPowerProximityStateController; + + // Tracks and manages the display state of the associated display. + private final DisplayStateController mDisplayStateController; + + + // Responsible for evaluating and tracking the automatic brightness relevant states. + // Todo: This is a temporary workaround. Ideally DPC2 should never talk to the strategies + private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; + // A record of state for skipping brightness ramps. private int mSkipRampState = RAMP_STATE_SKIP_NONE; @@ -500,81 +455,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private Sensor mLightSensor; private Sensor mScreenOffBrightnessSensor; - // The current brightness configuration. - @Nullable - private BrightnessConfiguration mBrightnessConfiguration; - - // The last brightness that was set by the user and not temporary. Set to - // PowerManager.BRIGHTNESS_INVALID_FLOAT when a brightness has yet to be recorded. - private float mLastUserSetScreenBrightness = Float.NaN; - - // The screen brightness setting has changed but not taken effect yet. If this is different - // from the current screen brightness setting then this is coming from something other than us - // and should be considered a user interaction. - private float mPendingScreenBrightnessSetting; - - // The last observed screen brightness setting, either set by us or by the settings app on - // behalf of the user. - private float mCurrentScreenBrightnessSetting; - - // The temporary screen brightness. Typically set when a user is interacting with the - // brightness slider but hasn't settled on a choice yet. Set to - // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set. - private float mTemporaryScreenBrightness; - - // This brightness value is set in concurrent displays mode. It is the brightness value - // of the lead display that this DPC should follow. - private float mBrightnessToFollow; - - // Indicates whether we should ramp slowly to the brightness value to follow. - private boolean mBrightnessToFollowSlowChange; - - // The last auto brightness adjustment that was set by the user and not temporary. Set to - // Float.NaN when an auto-brightness adjustment hasn't been recorded yet. - private float mAutoBrightnessAdjustment; - - // The pending auto brightness adjustment that will take effect on the next power state update. - private float mPendingAutoBrightnessAdjustment; - - // The temporary auto brightness adjustment. Typically set when a user is interacting with the - // adjustment slider but hasn't settled on a choice yet. Set to - // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set. - private float mTemporaryAutoBrightnessAdjustment; - - private boolean mUseAutoBrightness; - private boolean mIsRbcActive; - // Whether there's a callback to tell listeners the display has changed scheduled to run. When - // true it implies a wakelock is being held to guarantee the update happens before we collapse - // into suspend and so needs to be cleaned up if the thread is exiting. - // Should only be accessed on the Handler thread. - private boolean mOnStateChangedPending; - - // Count of proximity messages currently on this DPC's Handler. Used to keep track of how many - // suspend blocker acquisitions are pending when shutting down this DPC. - // Should only be accessed on the Handler thread. - private int mOnProximityPositiveMessages; - private int mOnProximityNegativeMessages; - // Animators. private ObjectAnimator mColorFadeOnAnimator; private ObjectAnimator mColorFadeOffAnimator; private DualRampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator; - private BrightnessSetting.BrightnessSettingListener mBrightnessSettingListener; - // True if this DisplayPowerController has been stopped and should no longer be running. + // True if this DisplayPowerController2 has been stopped and should no longer be running. private boolean mStopped; private DisplayDeviceConfig mDisplayDeviceConfig; - // Identifiers for suspend blocker acquisition requests - private final String mSuspendBlockerIdUnfinishedBusiness; - private final String mSuspendBlockerIdOnStateChanged; - private final String mSuspendBlockerIdProxPositive; - private final String mSuspendBlockerIdProxNegative; - private final String mSuspendBlockerIdProxDebounce; - private boolean mIsEnabled; private boolean mIsInTransition; private boolean mIsDisplayInternal; @@ -585,13 +477,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there // is one lead display, the additional displays follow the brightness value of the lead display. @GuardedBy("mLock") - private final SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers = - new SparseArray<>(); + private SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers = + new SparseArray(); private boolean mBootCompleted; private final DisplayManagerFlags mFlags; - private int mDozeStateOverride = Display.STATE_UNKNOWN; - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; + + private DisplayOffloadSession mDisplayOffloadSession; /** * Creates the display power controller. @@ -607,26 +499,28 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mClock = mInjector.getClock(); mLogicalDisplay = logicalDisplay; mDisplayId = mLogicalDisplay.getDisplayIdLocked(); - mTag = TAG + "[" + mDisplayId + "]"; - mHighBrightnessModeMetadata = hbmMetadata; - mSuspendBlockerIdUnfinishedBusiness = getSuspendBlockerUnfinishedBusinessId(mDisplayId); - mSuspendBlockerIdOnStateChanged = getSuspendBlockerOnStateChangedId(mDisplayId); - mSuspendBlockerIdProxPositive = getSuspendBlockerProxPositiveId(mDisplayId); - mSuspendBlockerIdProxNegative = getSuspendBlockerProxNegativeId(mDisplayId); - mSuspendBlockerIdProxDebounce = getSuspendBlockerProxDebounceId(mDisplayId); - - mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); - mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); - mDisplayStatsId = mUniqueDisplayId.hashCode(); + mSensorManager = sensorManager; + mHandler = new DisplayControllerHandler(handler.getLooper()); + mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked() + .getDisplayDeviceConfig(); mIsEnabled = logicalDisplay.isEnabledLocked(); mIsInTransition = logicalDisplay.isInTransitionLocked(); mIsDisplayInternal = logicalDisplay.getPrimaryDisplayDeviceLocked() .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL; - mHandler = new DisplayControllerHandler(handler.getLooper()); - mLastBrightnessEvent = new BrightnessEvent(mDisplayId); - mTempBrightnessEvent = new BrightnessEvent(mDisplayId); + mWakelockController = mInjector.getWakelockController(mDisplayId, callbacks); + mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController( + mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(), + () -> updatePowerState(), mDisplayId, mSensorManager); + mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); + mTag = TAG + "[" + mDisplayId + "]"; mThermalBrightnessThrottlingDataId = logicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId; + mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); + mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); + mDisplayStatsId = mUniqueDisplayId.hashCode(); + + mLastBrightnessEvent = new BrightnessEvent(mDisplayId); + mTempBrightnessEvent = new BrightnessEvent(mDisplayId); if (mDisplayId == Display.DEFAULT_DISPLAY) { mBatteryStats = BatteryStatsService.getService(); @@ -635,14 +529,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } mSettingsObserver = new SettingsObserver(mHandler); - mCallbacks = callbacks; - mSensorManager = sensorManager; mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); mBlanker = blanker; mContext = context; mBrightnessTracker = brightnessTracker; - // TODO: b/186428377 update brightness setting when display changes - mBrightnessSetting = brightnessSetting; mOnBrightnessChangeRunnable = onBrightnessChangeRunnable; PowerManager pm = context.getSystemService(PowerManager.class); @@ -650,30 +540,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final Resources resources = context.getResources(); // DOZE AND DIM SETTINGS - mScreenBrightnessDozeConfig = clampAbsoluteBrightness( + mScreenBrightnessDozeConfig = BrightnessUtils.clampAbsoluteBrightness( pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)); - mScreenBrightnessDimConfig = clampAbsoluteBrightness( - pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DIM)); - mScreenBrightnessMinimumDimAmount = resources.getFloat( - com.android.internal.R.dimen.config_screenBrightnessMinimumDimAmountFloat); - - - // NORMAL SCREEN SETTINGS - mScreenBrightnessDefault = clampAbsoluteBrightness( - mLogicalDisplay.getDisplayInfoLocked().brightnessDefault); - - mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing); - - mPersistBrightnessNitsForDefaultDisplay = resources.getBoolean( - com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay); - - mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked() - .getDisplayDeviceConfig(); - loadBrightnessRampRates(); mSkipScreenOnBrightnessRamp = resources.getBoolean( - com.android.internal.R.bool.config_skipScreenOnBrightnessRamp); + R.bool.config_skipScreenOnBrightnessRamp); + Runnable modeChangeCallback = () -> { sendUpdatePowerState(); postBrightnessChangeRunnable(); @@ -683,23 +555,38 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } }; - HighBrightnessModeController hbmController = createHbmControllerLocked(modeChangeCallback); + HighBrightnessModeController hbmController = createHbmControllerLocked(hbmMetadata, + modeChangeCallback); + mBrightnessThrottler = createBrightnessThrottlerLocked(); - mBrightnessRangeController = new BrightnessRangeController(hbmController, + mBrightnessRangeController = mInjector.getBrightnessRangeController(hbmController, modeChangeCallback, mDisplayDeviceConfig, mHandler, flags, mDisplayDevice.getDisplayTokenLocked(), mDisplayDevice.getDisplayDeviceInfoLocked()); - mBrightnessThrottler = createBrightnessThrottlerLocked(); + mDisplayBrightnessController = + new DisplayBrightnessController(context, null, + mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault, + brightnessSetting, () -> postBrightnessChangeRunnable(), + new HandlerExecutor(mHandler), flags); + mBrightnessClamperController = mInjector.getBrightnessClamperController( + mHandler, modeChangeCallback::run, + new BrightnessClamperController.DisplayDeviceData( + mUniqueDisplayId, + mThermalBrightnessThrottlingDataId, + logicalDisplay.getPowerThrottlingDataIdLocked(), + mDisplayDeviceConfig), mContext, flags); // Seed the cached brightness saveBrightnessInfo(getScreenBrightnessSetting()); + mAutomaticBrightnessStrategy = + mDisplayBrightnessController.getAutomaticBrightnessStrategy(); DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null; DisplayWhiteBalanceController displayWhiteBalanceController = null; if (mDisplayId == Display.DEFAULT_DISPLAY) { try { - displayWhiteBalanceController = injector.getDisplayWhiteBalanceController( + displayWhiteBalanceController = mInjector.getDisplayWhiteBalanceController( mHandler, mSensorManager, resources); displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler); displayWhiteBalanceSettings.setCallbacks(this); @@ -715,21 +602,24 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mDisplayId == Display.DEFAULT_DISPLAY) { mCdsi = LocalServices.getService(ColorDisplayServiceInternal.class); - boolean active = mCdsi.setReduceBrightColorsListener(new ReduceBrightColorsListener() { - @Override - public void onReduceBrightColorsActivationChanged(boolean activated, - boolean userInitiated) { - applyReduceBrightColorsSplineAdjustment(); - - } - - @Override - public void onReduceBrightColorsStrengthChanged(int strength) { + if (mCdsi != null) { + boolean active = mCdsi.setReduceBrightColorsListener( + new ReduceBrightColorsListener() { + @Override + public void onReduceBrightColorsActivationChanged(boolean activated, + boolean userInitiated) { + applyReduceBrightColorsSplineAdjustment(); + + } + + @Override + public void onReduceBrightColorsStrengthChanged(int strength) { + applyReduceBrightColorsSplineAdjustment(); + } + }); + if (active) { applyReduceBrightColorsSplineAdjustment(); } - }); - if (active) { - applyReduceBrightColorsSplineAdjustment(); } } else { mCdsi = null; @@ -737,27 +627,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call setUpAutoBrightness(context, handler); - mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic() + mColorFadeEnabled = mInjector.isColorFadeEnabled() && !resources.getBoolean( com.android.internal.R.bool.config_displayColorFadeDisabled); mColorFadeFadesConfig = resources.getBoolean( - com.android.internal.R.bool.config_animateScreenLights); + R.bool.config_animateScreenLights); mDisplayBlanksAfterDozeConfig = resources.getBoolean( - com.android.internal.R.bool.config_displayBlanksAfterDoze); + R.bool.config_displayBlanksAfterDoze); mBrightnessBucketsInDozeConfig = resources.getBoolean( - com.android.internal.R.bool.config_displayBrightnessBucketsInDoze); - - loadProximitySensor(); - - loadNitBasedBrightnessSetting(); - mBrightnessToFollow = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); - mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; + R.bool.config_displayBrightnessBucketsInDoze); mBootCompleted = bootCompleted; } @@ -785,7 +665,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call */ @Override public boolean isProximitySensorAvailable() { - return mProximitySensor != null; + return mDisplayPowerProximityStateController.isProximitySensorAvailable(); } /** @@ -818,64 +698,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - @Override - public int getDisplayId() { - return mDisplayId; - } - - @Override - public int getLeadDisplayId() { - return mLeadDisplayId; - } - - @Override - public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux, - boolean slowChange) { - mBrightnessRangeController.onAmbientLuxChange(ambientLux); - if (nits == BrightnessMappingStrategy.INVALID_NITS) { - mBrightnessToFollow = leadDisplayBrightness; - } else { - float brightness = getBrightnessFromNits(nits); - if (isValidBrightnessValue(brightness)) { - mBrightnessToFollow = brightness; - } else { - // The device does not support nits - mBrightnessToFollow = leadDisplayBrightness; - } - } - mBrightnessToFollowSlowChange = slowChange; - sendUpdatePowerState(); - } - - @Override - public void addDisplayBrightnessFollower(@NonNull DisplayPowerControllerInterface follower) { - synchronized (mLock) { - mDisplayBrightnessFollowers.append(follower.getDisplayId(), follower); - sendUpdatePowerStateLocked(); - } - } - - @Override - public void removeDisplayBrightnessFollower(@NonNull DisplayPowerControllerInterface follower) { - synchronized (mLock) { - mDisplayBrightnessFollowers.remove(follower.getDisplayId()); - mHandler.postAtTime(() -> follower.setBrightnessToFollow( - PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, - /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); - } - } - - @GuardedBy("mLock") - private void clearDisplayBrightnessFollowersLocked() { - for (int i = 0; i < mDisplayBrightnessFollowers.size(); i++) { - DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i); - mHandler.postAtTime(() -> follower.setBrightnessToFollow( - PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, - /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); - } - mDisplayBrightnessFollowers.clear(); - } - @Nullable @Override public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats( @@ -923,13 +745,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return true; } - boolean changed = false; - - if (waitForNegativeProximity - && !mPendingWaitForNegativeProximityLocked) { - mPendingWaitForNegativeProximityLocked = true; - changed = true; - } + boolean changed = mDisplayPowerProximityStateController + .setPendingWaitForNegativeProximityLocked(waitForNegativeProximity); if (mPendingRequestLocked == null) { mPendingRequestLocked = new DisplayPowerRequest(request); @@ -953,18 +770,23 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void overrideDozeScreenState(int displayState) { - synchronized (mLock) { - if (mDisplayOffloadSession == null || - !DisplayOffloadSession.isSupportedOffloadState(displayState)) { + mHandler.postAtTime(() -> { + if (mDisplayOffloadSession == null + || !(DisplayOffloadSession.isSupportedOffloadState(displayState) + || displayState == Display.STATE_UNKNOWN)) { return; } - mDozeStateOverride = displayState; + mDisplayStateController.overrideDozeScreenState(displayState); sendUpdatePowerState(); - } + }, mClock.uptimeMillis()); } @Override public void setDisplayOffloadSession(DisplayOffloadSession session) { + if (session == mDisplayOffloadSession) { + return; + } + unblockScreenOnByDisplayOffload(); mDisplayOffloadSession = session; } @@ -981,14 +803,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call * when displays get swapped on foldable devices. For example, different brightness properties * of each display need to be properly reflected in AutomaticBrightnessController. * - * Make sure DisplayManagerService.mSyncRoot is held when this is called + * Make sure DisplayManagerService.mSyncRoot lock is held when this is called */ @Override public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata, int leadDisplayId) { mLeadDisplayId = leadDisplayId; final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); if (device == null) { - Slog.wtf(mTag, "Display Device is null in DisplayPowerController for display: " + Slog.wtf(mTag, "Display Device is null in DisplayPowerController2 for display: " + mLogicalDisplay.getDisplayIdLocked()); return; } @@ -1004,6 +826,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL; final String thermalBrightnessThrottlingDataId = mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId; + final String powerThrottlingDataId = + mLogicalDisplay.getPowerThrottlingDataIdLocked(); + mHandler.postAtTime(() -> { boolean changed = false; if (mDisplayDevice != device) { @@ -1014,9 +839,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayDeviceConfig = config; mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; loadFromDisplayDeviceConfig(token, info, hbmMetadata); - loadNitBasedBrightnessSetting(); + mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config); - /// Since the underlying display-device changed, we really don't know the + // Since the underlying display-device changed, we really don't know the // last command that was sent to change it's state. Let's assume it is unknown so // that we trigger a change immediately. mPowerState.resetScreenState(); @@ -1034,7 +859,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mIsEnabled = isEnabled; mIsInTransition = isInTransition; } + mIsDisplayInternal = isDisplayInternal; + // using local variables here, when mBrightnessThrottler is removed, + // mThermalBrightnessThrottlingDataId could be removed as well + // changed = true will be not needed - clampers are maintaining their state and + // will call updatePowerState if needed. + mBrightnessClamperController.onDisplayChanged( + new BrightnessClamperController.DisplayDeviceData(uniqueId, + thermalBrightnessThrottlingDataId, powerThrottlingDataId, config)); + if (changed) { updatePowerState(); } @@ -1044,7 +878,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call /** * Unregisters all listeners and interrupts all running threads; halting future work. * - * This method should be called when the DisplayPowerController is no longer in use; i.e. when + * This method should be called when the DisplayPowerController2 is no longer in use; i.e. when * the {@link #mDisplayId display} has been removed. */ @Override @@ -1060,9 +894,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.stop(); } - if (mBrightnessSetting != null) { - mBrightnessSetting.unregisterListener(mBrightnessSettingListener); - } + mDisplayBrightnessController.stop(); mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); } @@ -1073,11 +905,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // All properties that depend on the associated DisplayDevice and the DDC must be // updated here. loadBrightnessRampRates(); - loadProximitySensor(); loadNitsRange(mContext.getResources()); setUpAutoBrightness(mContext, mHandler); reloadReduceBrightColours(); setAnimatorRampSpeeds(/* isIdleMode= */ false); + mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig); mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), @@ -1126,22 +958,30 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call noteScreenBrightness(mPowerState.getScreenBrightness()); // Initialize all of the brightness tracking state - final float brightness = convertToAdjustedNits(mPowerState.getScreenBrightness()); + final float brightness = mDisplayBrightnessController.convertToAdjustedNits( + mPowerState.getScreenBrightness()); if (mBrightnessTracker != null && brightness >= PowerManager.BRIGHTNESS_MIN) { mBrightnessTracker.start(brightness); } - mBrightnessSettingListener = brightnessValue -> { + + BrightnessSetting.BrightnessSettingListener brightnessSettingListener = brightnessValue -> { Message msg = mHandler.obtainMessage(MSG_UPDATE_BRIGHTNESS, brightnessValue); mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); }; + mDisplayBrightnessController + .registerBrightnessSettingChangeListener(brightnessSettingListener); - mBrightnessSetting.registerListener(mBrightnessSettingListener); mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); mContext.getContentResolver().registerContentObserver( Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); + if (mFlags.areAutoBrightnessModesEnabled()) { + mContext.getContentResolver().registerContentObserver( + Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_ALS), + /* notifyForDescendants= */ false, mSettingsObserver, UserHandle.USER_CURRENT); + } handleBrightnessModeChange(); } @@ -1165,12 +1005,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (isIdleScreenBrightnessEnabled) { BrightnessMappingStrategy idleModeBrightnessMapper = BrightnessMappingStrategy.create(context, mDisplayDeviceConfig, - AUTO_BRIGHTNESS_MODE_IDLE, mDisplayWhiteBalanceController); + AUTO_BRIGHTNESS_MODE_IDLE, + mDisplayWhiteBalanceController); if (idleModeBrightnessMapper != null) { - brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE, idleModeBrightnessMapper); + brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE, + idleModeBrightnessMapper); } } + BrightnessMappingStrategy dozeModeBrightnessMapper = + BrightnessMappingStrategy.create(context, mDisplayDeviceConfig, + AUTO_BRIGHTNESS_MODE_DOZE, mDisplayWhiteBalanceController); + if (mFlags.areAutoBrightnessModesEnabled() && dozeModeBrightnessMapper != null) { + brightnessMappers.put(AUTO_BRIGHTNESS_MODE_DOZE, dozeModeBrightnessMapper); + } + float userLux = BrightnessMappingStrategy.INVALID_LUX; float userNits = BrightnessMappingStrategy.INVALID_NITS; if (mAutomaticBrightnessController != null) { @@ -1180,7 +1029,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (defaultModeBrightnessMapper != null) { final float dozeScaleFactor = context.getResources().getFraction( - com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor, + R.fraction.config_screenAutoBrightnessDozeScaleFactor, 1, 1); // Ambient Lux - Active Mode Brightness Thresholds @@ -1264,14 +1113,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call long darkeningLightDebounceIdle = mDisplayDeviceConfig .getAutoBrightnessDarkeningLightDebounceIdle(); boolean autoBrightnessResetAmbientLuxAfterWarmUp = context.getResources().getBoolean( - com.android.internal.R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp); + R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp); int lightSensorWarmUpTimeConfig = context.getResources().getInteger( - com.android.internal.R.integer.config_lightSensorWarmupTime); + R.integer.config_lightSensorWarmupTime); int lightSensorRate = context.getResources().getInteger( - com.android.internal.R.integer.config_autoBrightnessLightSensorRate); + R.integer.config_autoBrightnessLightSensorRate); int initialLightSensorRate = context.getResources().getInteger( - com.android.internal.R.integer.config_autoBrightnessInitialLightSensorRate); + R.integer.config_autoBrightnessInitialLightSensorRate); if (initialLightSensorRate == -1) { initialLightSensorRate = lightSensorRate; } else if (initialLightSensorRate > lightSensorRate) { @@ -1301,7 +1150,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call screenBrightnessThresholdsIdle, mContext, mBrightnessRangeController, mBrightnessThrottler, mDisplayDeviceConfig.getAmbientHorizonShort(), mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userNits); + mDisplayBrightnessController.setAutomaticBrightnessController( + mAutomaticBrightnessController); + mAutomaticBrightnessStrategy + .setAutomaticBrightnessController(mAutomaticBrightnessController); mBrightnessEventRingBuffer = new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX); @@ -1351,7 +1204,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } else { Slog.w(mTag, "Screen brightness nits configuration is unavailable; falling back"); mNitsRange = BrightnessMappingStrategy.getFloatArray(resources - .obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits)); + .obtainTypedArray(R.array.config_screenBrightnessNits)); } } @@ -1369,7 +1222,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.switchMode(mode); setAnimatorRampSpeeds(isIdle); } - Message msg = mHandler.obtainMessage(); msg.what = MSG_SET_DWBC_STRONG_MODE; msg.arg1 = isIdle ? 1 : 0; @@ -1421,28 +1273,14 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call /** Clean up all resources that are accessed via the {@link #mHandler} thread. */ private void cleanupHandlerThreadAfterStop() { - setProximitySensorEnabled(false); + mDisplayPowerProximityStateController.cleanup(); mBrightnessRangeController.stop(); mBrightnessThrottler.stop(); + mBrightnessClamperController.stop(); mHandler.removeCallbacksAndMessages(null); // Release any outstanding wakelocks we're still holding because of pending messages. - if (mUnfinishedBusiness) { - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); - mUnfinishedBusiness = false; - } - if (mOnStateChangedPending) { - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); - mOnStateChangedPending = false; - } - for (int i = 0; i < mOnProximityPositiveMessages; i++) { - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); - } - mOnProximityPositiveMessages = 0; - for (int i = 0; i < mOnProximityNegativeMessages; i++) { - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); - } - mOnProximityNegativeMessages = 0; + mWakelockController.releaseAll(); final float brightness = mPowerState != null ? mPowerState.getScreenBrightness() @@ -1457,10 +1295,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.stop(); } + if (mDisplayWhiteBalanceController != null) { mDisplayWhiteBalanceController.setEnabled(false); } - } // Call from handler thread @@ -1476,7 +1314,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean mustNotify; final int previousPolicy; boolean mustInitialize = false; - int brightnessAdjustmentFlags = 0; mBrightnessReasonTemp.set(null); mTempBrightnessEvent.reset(); SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers; @@ -1491,7 +1328,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mPowerRequest == null) { mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); - updatePendingProximityRequestsLocked(); + mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mustInitialize = true; // Assume we're on and bright until told otherwise, since that's the state we turn @@ -1500,7 +1337,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } else if (mPendingRequestChangedLocked) { previousPolicy = mPowerRequest.policy; mPowerRequest.copyFrom(mPendingRequestLocked); - updatePendingProximityRequestsLocked(); + mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); mPendingRequestChangedLocked = false; mDisplayReadyLocked = false; } else { @@ -1512,105 +1349,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call displayBrightnessFollowers = mDisplayBrightnessFollowers.clone(); } - // Compute the basic display state using the policy. - // We might override this below based on other factors. - // Initialise brightness as invalid. - int state; - float brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT; - boolean performScreenOffTransition = false; - switch (mPowerRequest.policy) { - case DisplayPowerRequest.POLICY_OFF: - state = Display.STATE_OFF; - performScreenOffTransition = true; - break; - case DisplayPowerRequest.POLICY_DOZE: - if (mDozeStateOverride != Display.STATE_UNKNOWN) { - state = mDozeStateOverride; - } else if (mPowerRequest.dozeScreenState != Display.STATE_UNKNOWN) { - state = mPowerRequest.dozeScreenState; - } else { - state = Display.STATE_DOZE; - } - if (!mAllowAutoBrightnessWhileDozingConfig) { - brightnessState = mPowerRequest.dozeScreenBrightness; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE); - } - break; - case DisplayPowerRequest.POLICY_DIM: - case DisplayPowerRequest.POLICY_BRIGHT: - default: - state = Display.STATE_ON; - break; - } - assert (state != Display.STATE_UNKNOWN); - - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness - && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE - && !mAllowAutoBrightnessWhileDozingConfig)) - && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); - } - - boolean skipRampBecauseOfProximityChangeToNegative = false; - // Apply the proximity sensor. - if (mProximitySensor != null) { - if (mPowerRequest.useProximitySensor && state != Display.STATE_OFF) { - // At this point the policy says that the screen should be on, but we've been - // asked to listen to the prox sensor to adjust the display state, so lets make - // sure the sensor is on. - setProximitySensorEnabled(true); - if (!mScreenOffBecauseOfProximity - && mProximity == PROXIMITY_POSITIVE - && !mIgnoreProximityUntilChanged) { - // Prox sensor already reporting "near" so we should turn off the screen. - // Also checked that we aren't currently set to ignore the proximity sensor - // temporarily. - mScreenOffBecauseOfProximity = true; - sendOnProximityPositiveWithWakelock(); - } - } else if (mWaitingForNegativeProximity - && mScreenOffBecauseOfProximity - && mProximity == PROXIMITY_POSITIVE - && state != Display.STATE_OFF) { - // The policy says that we should have the screen on, but it's off due to the prox - // and we've been asked to wait until the screen is far from the user to turn it - // back on. Let keep the prox sensor on so we can tell when it's far again. - setProximitySensorEnabled(true); - } else { - // We haven't been asked to use the prox sensor and we're not waiting on the screen - // to turn back on...so lets shut down the prox sensor. - setProximitySensorEnabled(false); - mWaitingForNegativeProximity = false; - } - - if (mScreenOffBecauseOfProximity - && (mProximity != PROXIMITY_POSITIVE || mIgnoreProximityUntilChanged)) { - // The screen *was* off due to prox being near, but now it's "far" so lets turn - // the screen back on. Also turn it back on if we've been asked to ignore the - // prox sensor temporarily. - mScreenOffBecauseOfProximity = false; - skipRampBecauseOfProximityChangeToNegative = true; - sendOnProximityNegativeWithWakelock(); - } - } else { - setProximitySensorEnabled(false); - mWaitingForNegativeProximity = false; - mIgnoreProximityUntilChanged = false; - - if (mScreenOffBecauseOfProximity) { - // The screen *was* off due to prox being near, but now there's no prox sensor, so - // let's turn the screen back on. - mScreenOffBecauseOfProximity = false; - skipRampBecauseOfProximityChangeToNegative = true; - sendOnProximityNegativeWithWakelock(); - } - } - - if (!mIsEnabled - || mIsInTransition - || mScreenOffBecauseOfProximity) { - state = Display.STATE_OFF; - } + int state = mDisplayStateController + .updateDisplayState(mPowerRequest, mIsEnabled, mIsInTransition); // Initialize things the first time the power state is changed. if (mustInitialize) { @@ -1620,157 +1360,100 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Animate the screen state change unless already animating. // The transition may be deferred, so after this point we will use the // actual state instead of the desired one. - final int oldState = mPowerState.getScreenState(); - animateScreenStateChange(state, performScreenOffTransition); + animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition()); state = mPowerState.getScreenState(); - boolean slowChange = false; - if (state == Display.STATE_OFF) { - brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF); + // Switch to doze auto-brightness mode if needed + if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null + && !mAutomaticBrightnessController.isInIdleMode()) { + setAutomaticScreenBrightnessMode(Display.isDozeState(state) + ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); } - if (Float.isNaN(brightnessState) && isValidBrightnessValue(mBrightnessToFollow)) { - brightnessState = mBrightnessToFollow; - slowChange = mBrightnessToFollowSlowChange; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_FOLLOWER); - } + final boolean userSetBrightnessChanged = mDisplayBrightnessController + .updateUserSetScreenBrightness(); - if ((Float.isNaN(brightnessState)) - && isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) { - brightnessState = mPowerRequest.screenBrightnessOverride; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_OVERRIDE); - mAppliedScreenBrightnessOverride = true; - } else { - mAppliedScreenBrightnessOverride = false; - } - - final boolean autoBrightnessEnabledInDoze = - mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state); - final boolean autoBrightnessEnabled = mUseAutoBrightness - && (state == Display.STATE_ON || autoBrightnessEnabledInDoze) - && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_OVERRIDE - && mAutomaticBrightnessController != null; - final boolean autoBrightnessDisabledDueToDisplayOff = mUseAutoBrightness - && !(state == Display.STATE_ON || autoBrightnessEnabledInDoze); - final int autoBrightnessState = autoBrightnessEnabled - && mBrightnessReasonTemp.getReason() != BrightnessReason.REASON_FOLLOWER - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED - : autoBrightnessDisabledDueToDisplayOff - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE - : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED; - - final boolean userSetBrightnessChanged = updateUserSetScreenBrightness(); + DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController + .updateBrightness(mPowerRequest, state); + float brightnessState = displayBrightnessState.getBrightness(); + float rawBrightnessState = displayBrightnessState.getBrightness(); + mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason()); + boolean slowChange = displayBrightnessState.isSlowChange(); + // custom transition duration + float customAnimationRate = displayBrightnessState.getCustomAnimationRate(); - // Use the temporary screen brightness if there isn't an override, either from - // WindowManager or based on the display state. - if (isValidBrightnessValue(mTemporaryScreenBrightness)) { - brightnessState = mTemporaryScreenBrightness; - mAppliedTemporaryBrightness = true; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY); - } else { - mAppliedTemporaryBrightness = false; + // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor + // doesn't yet have a valid lux value to use with auto-brightness. + if (mScreenOffBrightnessSensorController != null) { + mScreenOffBrightnessSensorController + .setLightSensorEnabled(displayBrightnessState.getShouldUseAutoBrightness() + && mIsEnabled && (state == Display.STATE_OFF + || (state == Display.STATE_DOZE + && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())) + && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); } - final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment(); - - // Use the autobrightness adjustment override if set. - final float autoBrightnessAdjustment; - if (!Float.isNaN(mTemporaryAutoBrightnessAdjustment)) { - autoBrightnessAdjustment = mTemporaryAutoBrightnessAdjustment; - brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO_TEMP; - mAppliedTemporaryAutoBrightnessAdjustment = true; - } else { - autoBrightnessAdjustment = mAutoBrightnessAdjustment; - brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO; - mAppliedTemporaryAutoBrightnessAdjustment = false; - } - // Apply brightness boost. - // We do this here after deciding whether auto-brightness is enabled so that we don't - // disable the light sensor during this temporary state. That way when boost ends we will - // be able to resume normal auto-brightness behavior without any delay. - if (mPowerRequest.boostScreenBrightness - && brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT) { - brightnessState = PowerManager.BRIGHTNESS_MAX; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_BOOST); - mAppliedBrightnessBoost = true; - } else { - mAppliedBrightnessBoost = false; - } + // Take note if the short term model was already active before applying the current + // request changes. + final boolean wasShortTermModelActive = + mAutomaticBrightnessStrategy.isShortTermModelActive(); + mAutomaticBrightnessStrategy.setAutoBrightnessState(state, + mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(), + mBrightnessReasonTemp.getReason(), mPowerRequest.policy, + mDisplayBrightnessController.getLastUserSetScreenBrightness(), + userSetBrightnessChanged); // If the brightness is already set then it's been overridden by something other than the // user, or is a temporary adjustment. boolean userInitiatedChange = (Float.isNaN(brightnessState)) - && (autoBrightnessAdjustmentChanged || userSetBrightnessChanged); - boolean wasShortTermModelActive = false; - // Configure auto-brightness. - if (mAutomaticBrightnessController != null) { - wasShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints(); - mAutomaticBrightnessController.configure(autoBrightnessState, - mBrightnessConfiguration, - mLastUserSetScreenBrightness, - userSetBrightnessChanged, autoBrightnessAdjustment, - autoBrightnessAdjustmentChanged, mPowerRequest.policy, - mShouldResetShortTermModel); - mShouldResetShortTermModel = false; - } - mBrightnessRangeController.setAutoBrightnessEnabled(autoBrightnessEnabled + && (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged() + || userSetBrightnessChanged); + + mBrightnessRangeController.setAutoBrightnessEnabled( + mAutomaticBrightnessStrategy.isAutoBrightnessEnabled() ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED - : autoBrightnessDisabledDueToDisplayOff + : mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff() ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); - if (mBrightnessTracker != null) { - mBrightnessTracker.setShouldCollectColorSample(mBrightnessConfiguration != null - && mBrightnessConfiguration.shouldCollectColorSamples()); - } - - boolean updateScreenBrightnessSetting = false; - float rawBrightnessState = brightnessState; - + boolean updateScreenBrightnessSetting = + displayBrightnessState.shouldUpdateScreenBrightnessSetting(); + float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness(); // Apply auto-brightness. + int brightnessAdjustmentFlags = 0; if (Float.isNaN(brightnessState)) { - float newAutoBrightnessAdjustment = autoBrightnessAdjustment; - if (autoBrightnessEnabled) { - rawBrightnessState = mAutomaticBrightnessController - .getRawAutomaticScreenBrightness(); - brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness( + if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) { + brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness( mTempBrightnessEvent); - newAutoBrightnessAdjustment = - mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment(); - } - if (isValidBrightnessValue(brightnessState) - || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) { - // Use current auto-brightness value and slowly adjust to changes. - brightnessState = clampScreenBrightness(brightnessState); - if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) { - slowChange = true; // slowly adapt to auto-brightness - } - updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState; - mAppliedAutoBrightness = true; - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC); - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.setLightSensorEnabled(false); + if (BrightnessUtils.isValidBrightnessValue(brightnessState) + || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) { + rawBrightnessState = mAutomaticBrightnessController + .getRawAutomaticScreenBrightness(); + brightnessState = clampScreenBrightness(brightnessState); + // slowly adapt to auto-brightness + // TODO(b/253226419): slowChange should be decided by strategy.updateBrightness + slowChange = mAutomaticBrightnessStrategy.hasAppliedAutoBrightness() + && !mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged(); + brightnessAdjustmentFlags = + mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags(); + updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; + mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true); + mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC); + if (mScreenOffBrightnessSensorController != null) { + mScreenOffBrightnessSensorController.setLightSensorEnabled(false); + } + } else { + mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false); } - } else { - mAppliedAutoBrightness = false; - } - if (autoBrightnessAdjustment != newAutoBrightnessAdjustment) { - // If the autobrightness controller has decided to change the adjustment value - // used, make sure that's reflected in settings. - putAutoBrightnessAdjustmentSetting(newAutoBrightnessAdjustment); - } else { - // Adjustment values resulted in no change - brightnessAdjustmentFlags = 0; } } else { // Any non-auto-brightness values such as override or temporary should still be subject // to clamping so that they don't go beyond the current max as specified by HBM // Controller. brightnessState = clampScreenBrightness(brightnessState); - mAppliedAutoBrightness = false; - brightnessAdjustmentFlags = 0; + mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false); } + // Use default brightness when dozing unless overridden. if ((Float.isNaN(brightnessState)) && Display.isDozeState(state)) { @@ -1781,14 +1464,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // The ALS is not available yet - use the screen off sensor to determine the initial // brightness - if (Float.isNaN(brightnessState) && autoBrightnessEnabled + if (Float.isNaN(brightnessState) && mAutomaticBrightnessStrategy.isAutoBrightnessEnabled() && mScreenOffBrightnessSensorController != null) { rawBrightnessState = mScreenOffBrightnessSensorController.getAutomaticScreenBrightness(); brightnessState = rawBrightnessState; - if (isValidBrightnessValue(brightnessState)) { + if (BrightnessUtils.isValidBrightnessValue(brightnessState)) { brightnessState = clampScreenBrightness(brightnessState); - updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState; + updateScreenBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness() + != brightnessState; mBrightnessReasonTemp.setReason( BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR); } @@ -1796,9 +1480,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Apply manual brightness. if (Float.isNaN(brightnessState)) { - rawBrightnessState = mCurrentScreenBrightnessSetting; + rawBrightnessState = currentBrightnessSetting; brightnessState = clampScreenBrightness(rawBrightnessState); - if (brightnessState != mCurrentScreenBrightnessSetting) { + if (brightnessState != currentBrightnessSetting) { // The manually chosen screen brightness is outside of the currently allowed // range (i.e., high-brightness-mode), make sure we tell the rest of the system // by updating the setting. @@ -1811,7 +1495,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call : mAutomaticBrightnessController.getAmbientLux(); for (int i = 0; i < displayBrightnessFollowers.size(); i++) { DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i); - follower.setBrightnessToFollow(rawBrightnessState, convertToNits(rawBrightnessState), + follower.setBrightnessToFollow(rawBrightnessState, + mDisplayBrightnessController.convertToNits(rawBrightnessState), ambientLux, slowChange); } @@ -1823,64 +1508,25 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Note throttling effectively changes the allowed brightness range, so, similarly to HBM, // we broadcast this change through setting. final float unthrottledBrightnessState = brightnessState; - if (mBrightnessThrottler.isThrottled()) { - mTempBrightnessEvent.setThermalMax(mBrightnessThrottler.getBrightnessCap()); - brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap()); - mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED); - if (!mAppliedThrottling) { - // Brightness throttling is needed, so do so quickly. - // Later, when throttling is removed, we let other mechanisms decide on speed. - slowChange = false; - } - mAppliedThrottling = true; - } else if (mAppliedThrottling) { - mAppliedThrottling = false; - } + DisplayBrightnessState clampedState = mBrightnessClamperController.clamp(mPowerRequest, + brightnessState, slowChange); + + brightnessState = clampedState.getBrightness(); + slowChange = clampedState.isSlowChange(); + // faster rate wins, at this point customAnimationRate == -1, strategy does not control + // customAnimationRate. Should be revisited if strategy start setting this value + customAnimationRate = Math.max(customAnimationRate, clampedState.getCustomAnimationRate()); + mBrightnessReasonTemp.addModifier(clampedState.getBrightnessReason().getModifier()); if (updateScreenBrightnessSetting) { // Tell the rest of the system about the new brightness in case we had to change it // for things like auto-brightness or high-brightness-mode. Note that we do this - // before applying the low power or dim transformations so that the slider - // accurately represents the full possible range, even if they range changes what - // it means in absolute terms. - updateScreenBrightnessSetting(brightnessState); - } - - // Apply dimming by at least some minimum amount when user activity - // timeout is about to expire. - if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) { - if (brightnessState > PowerManager.BRIGHTNESS_MIN) { - brightnessState = Math.max( - Math.min(brightnessState - mScreenBrightnessMinimumDimAmount, - mScreenBrightnessDimConfig), - PowerManager.BRIGHTNESS_MIN); - mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_DIMMED); - } - if (!mAppliedDimming) { - slowChange = false; - } - mAppliedDimming = true; - } else if (mAppliedDimming) { - slowChange = false; - mAppliedDimming = false; - } - // If low power mode is enabled, scale brightness by screenLowPowerBrightnessFactor - // as long as it is above the minimum threshold. - if (mPowerRequest.lowPowerMode) { - if (brightnessState > PowerManager.BRIGHTNESS_MIN) { - final float brightnessFactor = - Math.min(mPowerRequest.screenLowPowerBrightnessFactor, 1); - final float lowPowerBrightnessFloat = (brightnessState * brightnessFactor); - brightnessState = Math.max(lowPowerBrightnessFloat, PowerManager.BRIGHTNESS_MIN); - mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_LOW_POWER); - } - if (!mAppliedLowPower) { - slowChange = false; - } - mAppliedLowPower = true; - } else if (mAppliedLowPower) { - slowChange = false; - mAppliedLowPower = false; + // only considering maxBrightness (ignoring brightness modifiers like low power or dim) + // so that the slider accurately represents the full possible range, + // even if they range changes what it means in absolute terms. + mDisplayBrightnessController.updateScreenBrightnessSetting( + MathUtils.constrain(unthrottledBrightnessState, + clampedState.getMinBrightness(), clampedState.getMaxBrightness())); } // The current brightness to use has been calculated at this point, and HbmController should @@ -1889,13 +1535,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // brightness sources (such as an app override) are not saved to the setting, but should be // reflected in HBM calculations. mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, - mBrightnessThrottler.getBrightnessMaxReason()); + mBrightnessClamperController.getBrightnessMaxReason()); // Animate the screen brightness when the screen is on or dozing. - // Skip the animation when the screen is off. + // Skip the animation when the screen is off or suspended. boolean brightnessAdjusted = false; final boolean brightnessIsTemporary = - mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment; + (mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_TEMPORARY) + || mAutomaticBrightnessStrategy + .isTemporaryAutoBrightnessAdjustmentApplied(); if (!mPendingScreenOff) { if (mSkipScreenOnBrightnessRamp) { if (state == Display.STATE_ON) { @@ -1916,7 +1564,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState - != RAMP_STATE_SKIP_NONE) || skipRampBecauseOfProximityChangeToNegative; + != RAMP_STATE_SKIP_NONE) || mDisplayPowerProximityStateController + .shouldSkipRampBecauseOfProximityChangeToNegative(); // While dozing, sometimes the brightness is split into buckets. Rather than animating // through the buckets, which is unlikely to be smooth in the first place, just jump // right to the suggested brightness. @@ -1950,13 +1599,25 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // We want to scale HDR brightness level with the SDR level, we also need to restore // SDR brightness immediately when entering dim or low power mode. animateValue = mBrightnessRangeController.getHdrBrightnessValue(); + customAnimationRate = Math.max(customAnimationRate, + mBrightnessRangeController.getHdrTransitionRate()); mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_HDR); } + // if doze or suspend state is requested, we want to finish brightnes animation fast + // to allow state animation to start + if (mPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE + && (mPowerRequest.dozeScreenState == Display.STATE_UNKNOWN // dozing + || mPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND + || mPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND)) { + customAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; + slowChange = false; + } + final float currentBrightness = mPowerState.getScreenBrightness(); final float currentSdrBrightness = mPowerState.getSdrScreenBrightness(); - if (isValidBrightnessValue(animateValue) + if (BrightnessUtils.isValidBrightnessValue(animateValue) && (animateValue != currentBrightness || sdrAnimateValue != currentSdrBrightness)) { boolean skipAnimation = initialRampSkip || hasBrightnessBuckets @@ -1986,6 +1647,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (skipAnimation) { animateScreenBrightness(animateValue, sdrAnimateValue, SCREEN_ANIMATION_RATE_MINIMUM); + } else if (customAnimationRate > 0) { + animateScreenBrightness(animateValue, sdrAnimateValue, + customAnimationRate, /* ignoreAnimationLimits = */true); } else { boolean isIncreasing = animateValue > currentBrightness; final float rampSpeed; @@ -2007,13 +1671,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange, - wasShortTermModelActive, autoBrightnessEnabled, brightnessIsTemporary); + wasShortTermModelActive, mAutomaticBrightnessStrategy.isAutoBrightnessEnabled(), + brightnessIsTemporary, displayBrightnessState.getShouldUseAutoBrightness()); // We save the brightness info *after* the brightness setting has been changed and // adjustments made so that the brightness info reflects the latest value. - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), animateValue); + brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), + animateValue, clampedState); } else { - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting()); + brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), clampedState); } // Only notify if the brightness adjustment is not temporary (i.e. slider has been released) @@ -2049,13 +1715,20 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call ? mCdsi.getReduceBrightColorsStrength() : -1); mTempBrightnessEvent.setPowerFactor(mPowerRequest.screenLowPowerBrightnessFactor); mTempBrightnessEvent.setWasShortTermModelActive(wasShortTermModelActive); - mTempBrightnessEvent.setAutomaticBrightnessEnabled(mUseAutoBrightness); + mTempBrightnessEvent.setDisplayBrightnessStrategyName(displayBrightnessState + .getDisplayBrightnessStrategyName()); + mTempBrightnessEvent.setAutomaticBrightnessEnabled( + displayBrightnessState.getShouldUseAutoBrightness()); // Temporary is what we use during slider interactions. We avoid logging those so that // we don't spam logcat when the slider is being used. boolean tempToTempTransition = mTempBrightnessEvent.getReason().getReason() == BrightnessReason.REASON_TEMPORARY && mLastBrightnessEvent.getReason().getReason() == BrightnessReason.REASON_TEMPORARY; + // Purely for dumpsys; + final boolean isRbcEvent = + mLastBrightnessEvent.isRbcEnabled() != mTempBrightnessEvent.isRbcEnabled(); + if ((!mTempBrightnessEvent.equalsMainData(mLastBrightnessEvent) && !tempToTempTransition) || brightnessAdjustmentFlags != 0) { mTempBrightnessEvent.setInitialBrightness(mLastBrightnessEvent.getBrightness()); @@ -2075,6 +1748,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mBrightnessEventRingBuffer != null) { mBrightnessEventRingBuffer.append(newEvent); } + if (isRbcEvent) { + mRbcEventRingBuffer.append(newEvent); + } + } // Update display white-balance. @@ -2092,6 +1769,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // reporting the display is ready because we only need to ensure the screen is in the // right power state even as it continues to converge on the desired brightness. final boolean ready = mPendingScreenOnUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null && (!mColorFadeEnabled || (!mColorFadeOnAnimator.isStarted() && !mColorFadeOffAnimator.isStarted())) && mPowerState.waitUntilClean(mCleanListener); @@ -2106,12 +1784,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Grab a wake lock if we have unfinished business. - if (!finished && !mUnfinishedBusiness) { - if (DEBUG) { - Slog.d(mTag, "Unfinished business..."); - } - mCallbacks.acquireSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); - mUnfinishedBusiness = true; + if (!finished) { + mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); } // Notify the power manager when ready. @@ -2130,12 +1804,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Release the wake lock when we have no unfinished business. - if (finished && mUnfinishedBusiness) { - if (DEBUG) { - Slog.d(mTag, "Finished business..."); - } - mUnfinishedBusiness = false; - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdUnfinishedBusiness); + if (finished) { + mWakelockController.releaseWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); } // Record if dozing for future comparison. @@ -2166,9 +1836,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private void setDwbcLoggingEnabled(int arg) { if (mDisplayWhiteBalanceController != null) { - final boolean shouldEnable = (arg == 1); - mDisplayWhiteBalanceController.setLoggingEnabled(shouldEnable); - mDisplayWhiteBalanceSettings.setLoggingEnabled(shouldEnable); + final boolean enabled = (arg == 1); + mDisplayWhiteBalanceController.setLoggingEnabled(enabled); + mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled); } } @@ -2183,7 +1853,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call */ @Override public void ignoreProximitySensorUntilChanged() { - mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY); + mDisplayPowerProximityStateController.ignoreProximitySensorUntilChanged(); } @Override @@ -2210,21 +1880,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call @Override public void setBrightnessFromOffload(float brightness) { - // The old DPC is no longer supported + Message msg = mHandler.obtainMessage(MSG_SET_BRIGHTNESS_FROM_OFFLOAD, + Float.floatToIntBits(brightness), 0 /*unused*/); + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); } @Override public float[] getAutoBrightnessLevels( @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - // The old DPC is no longer supported - return null; + int preset = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, + Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, UserHandle.USER_CURRENT); + return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(mode, preset); } @Override public float[] getAutoBrightnessLuxLevels( @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - // The old DPC is no longer supported - return null; + int preset = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, + Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, UserHandle.USER_CURRENT); + return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode, preset); } @Override @@ -2241,18 +1917,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + @Override + public void onBootCompleted() { + Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED); + mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); + } + private boolean saveBrightnessInfo(float brightness) { - return saveBrightnessInfo(brightness, brightness); + return saveBrightnessInfo(brightness, /* state= */ null); + } + + private boolean saveBrightnessInfo(float brightness, @Nullable DisplayBrightnessState state) { + return saveBrightnessInfo(brightness, brightness, state); } - private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) { + private boolean saveBrightnessInfo(float brightness, float adjustedBrightness, + @Nullable DisplayBrightnessState state) { synchronized (mCachedBrightnessInfo) { - final float minBrightness = Math.min( - mBrightnessRangeController.getCurrentBrightnessMin(), - mBrightnessThrottler.getBrightnessCap()); + float stateMax = state != null ? state.getMaxBrightness() : PowerManager.BRIGHTNESS_MAX; + float stateMin = state != null ? state.getMinBrightness() : PowerManager.BRIGHTNESS_MAX; + final float minBrightness = Math.max(stateMin, Math.min( + mBrightnessRangeController.getCurrentBrightnessMin(), stateMax)); final float maxBrightness = Math.min( - mBrightnessRangeController.getCurrentBrightnessMax(), - mBrightnessThrottler.getBrightnessCap()); + mBrightnessRangeController.getCurrentBrightnessMax(), stateMax); boolean changed = false; changed |= @@ -2275,8 +1962,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRangeController.getTransitionPoint()); changed |= mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason, - mBrightnessThrottler.getBrightnessMaxReason()); - + mBrightnessClamperController.getBrightnessMaxReason()); return changed; } } @@ -2288,27 +1974,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private HighBrightnessModeController createHbmControllerLocked( - Runnable modeChangeCallback) { - final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); - final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); - final IBinder displayToken = - mLogicalDisplay.getPrimaryDisplayDeviceLocked().getDisplayTokenLocked(); - final String displayUniqueId = - mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); + HighBrightnessModeMetadata hbmMetadata, Runnable modeChangeCallback) { + final DisplayDeviceConfig ddConfig = mDisplayDevice.getDisplayDeviceConfig(); + final IBinder displayToken = mDisplayDevice.getDisplayTokenLocked(); + final String displayUniqueId = mDisplayDevice.getUniqueId(); final DisplayDeviceConfig.HighBrightnessModeData hbmData = ddConfig != null ? ddConfig.getHighBrightnessModeData() : null; - final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); + final DisplayDeviceInfo info = mDisplayDevice.getDisplayDeviceInfoLocked(); return mInjector.getHighBrightnessModeController(mHandler, info.width, info.height, displayToken, displayUniqueId, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX, hbmData, - new HighBrightnessModeController.HdrBrightnessDeviceConfig() { - @Override - public float getHdrBrightnessFromSdr( - float sdrBrightness, float maxDesiredHdrSdrRatio) { - return mDisplayDeviceConfig.getHdrBrightnessFromSdr( - sdrBrightness, maxDesiredHdrSdrRatio); - } - }, modeChangeCallback, mHighBrightnessModeMetadata, mContext); + PowerManager.BRIGHTNESS_MAX, hbmData, (sdrBrightness, maxDesiredHdrSdrRatio) -> + mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness, + maxDesiredHdrSdrRatio), modeChangeCallback, hbmMetadata, mContext); } private BrightnessThrottler createBrightnessThrottlerLocked() { @@ -2359,18 +2036,72 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + private void blockScreenOnByDisplayOffload(DisplayOffloadSession displayOffloadSession) { + if (mPendingScreenOnUnblockerByDisplayOffload != null || displayOffloadSession == null) { + return; + } + mScreenTurningOnWasBlockedByDisplayOffload = true; + + Trace.asyncTraceBegin( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + mScreenOnBlockByDisplayOffloadStartRealTime = SystemClock.elapsedRealtime(); + + mPendingScreenOnUnblockerByDisplayOffload = + () -> onDisplayOffloadUnblockScreenOn(displayOffloadSession); + if (!displayOffloadSession.blockScreenOn(mPendingScreenOnUnblockerByDisplayOffload)) { + mPendingScreenOnUnblockerByDisplayOffload = null; + long delay = + SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; + Slog.w(mTag, "Tried blocking screen on for offloading but failed. So, end trace after " + + delay + " ms."); + Trace.asyncTraceEnd( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + return; + } + Slog.i(mTag, "Blocking screen on for offloading."); + } + + private void onDisplayOffloadUnblockScreenOn(DisplayOffloadSession displayOffloadSession) { + Message msg = mHandler.obtainMessage(MSG_OFFLOADING_SCREEN_ON_UNBLOCKED, + displayOffloadSession); + mHandler.sendMessage(msg); + } + + private void unblockScreenOnByDisplayOffload() { + if (mPendingScreenOnUnblockerByDisplayOffload == null) { + return; + } + mPendingScreenOnUnblockerByDisplayOffload = null; + long delay = SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; + Slog.i(mTag, "Unblocked screen on for offloading after " + delay + " ms"); + Trace.asyncTraceEnd( + Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); + } + private boolean setScreenState(int state) { return setScreenState(state, false /*reportOnly*/); } private boolean setScreenState(int state, boolean reportOnly) { final boolean isOff = (state == Display.STATE_OFF); + final boolean isOn = (state == Display.STATE_ON); + final boolean changed = mPowerState.getScreenState() != state; + + // If the screen is turning on, give displayoffload a chance to do something before the + // screen actually turns on. + // TODO(b/316941732): add tests for this displayoffload screen-on blocker. + if (isOn && changed && !mScreenTurningOnWasBlockedByDisplayOffload) { + blockScreenOnByDisplayOffload(mDisplayOffloadSession); + } else if (!isOn && mScreenTurningOnWasBlockedByDisplayOffload) { + // No longer turning screen on, so unblock previous screen on blocking immediately. + unblockScreenOnByDisplayOffload(); + mScreenTurningOnWasBlockedByDisplayOffload = false; + } - if (mPowerState.getScreenState() != state - || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { + if (changed || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { // If we are trying to turn screen off, give policy a chance to do something before we // actually turn the screen off. - if (isOff && !mScreenOffBecauseOfProximity) { + if (isOff && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF); @@ -2383,8 +2114,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - if (!reportOnly && mPowerState.getScreenState() != state - && readyToUpdateDisplayState()) { + if (!reportOnly && changed && readyToUpdateDisplayState() + && mPendingScreenOffUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); String propertyKey = "debug.tracing.screen_state"; @@ -2410,7 +2142,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // it is only removed once the window manager tells us that the activity has // finished drawing underneath. if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF - && !mScreenOffBecauseOfProximity) { + && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); unblockScreenOn(); mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition); @@ -2436,12 +2168,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Return true if the screen isn't blocked. - return mPendingScreenOnUnblocker == null; + return mPendingScreenOnUnblocker == null + && mPendingScreenOnUnblockerByDisplayOffload == null; } private void setReportedScreenState(int state) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "ReportedScreenStateToPolicy", state); mReportedScreenStateToPolicy = state; + if (state == REPORTED_TO_POLICY_SCREEN_ON) { + mScreenTurningOnWasBlockedByDisplayOffload = false; + } } private void loadAmbientLightSensor() { @@ -2456,18 +2192,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayDeviceConfig.getScreenOffBrightnessSensor(), SensorUtils.NO_FALLBACK); } - private void loadProximitySensor() { - if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT || mDisplayId != Display.DEFAULT_DISPLAY) { - return; - } - mProximitySensor = SensorUtils.findSensor(mSensorManager, - mDisplayDeviceConfig.getProximitySensor(), Sensor.TYPE_PROXIMITY); - if (mProximitySensor != null) { - mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(), - TYPICAL_PROXIMITY_THRESHOLD); - } - } - private float clampScreenBrightness(float value) { if (Float.isNaN(value)) { value = PowerManager.BRIGHTNESS_MIN; @@ -2476,18 +2200,18 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mBrightnessRangeController.getCurrentBrightnessMax()); } - // Checks whether the brightness is within the valid brightness range, not including off. - private boolean isValidBrightnessValue(float brightness) { - return brightness >= PowerManager.BRIGHTNESS_MIN - && brightness <= PowerManager.BRIGHTNESS_MAX; + private void animateScreenBrightness(float target, float sdrTarget, float rate) { + animateScreenBrightness(target, sdrTarget, rate, /* ignoreAnimationLimits = */false); } - private void animateScreenBrightness(float target, float sdrTarget, float rate) { + private void animateScreenBrightness(float target, float sdrTarget, float rate, + boolean ignoreAnimationLimits) { if (DEBUG) { Slog.d(mTag, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget + ", rate=" + rate); } - if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate, false)) { + if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate, + ignoreAnimationLimits)) { Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target); String propertyKey = "debug.tracing.screen_brightness"; @@ -2655,102 +2379,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call private final Runnable mCleanListener = this::sendUpdatePowerState; - private void setProximitySensorEnabled(boolean enable) { - if (enable) { - if (!mProximitySensorEnabled) { - // Register the listener. - // Proximity sensor state already cleared initially. - mProximitySensorEnabled = true; - mIgnoreProximityUntilChanged = false; - mSensorManager.registerListener(mProximitySensorListener, mProximitySensor, - SensorManager.SENSOR_DELAY_NORMAL, mHandler); - } - } else { - if (mProximitySensorEnabled) { - // Unregister the listener. - // Clear the proximity sensor state for next time. - mProximitySensorEnabled = false; - mProximity = PROXIMITY_UNKNOWN; - mIgnoreProximityUntilChanged = false; - mPendingProximity = PROXIMITY_UNKNOWN; - mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); - mSensorManager.unregisterListener(mProximitySensorListener); - clearPendingProximityDebounceTime(); // release wake lock (must be last) - } - } - } - - private void handleProximitySensorEvent(long time, boolean positive) { - if (mProximitySensorEnabled) { - if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) { - return; // no change - } - if (mPendingProximity == PROXIMITY_POSITIVE && positive) { - return; // no change - } - - // Only accept a proximity sensor reading if it remains - // stable for the entire debounce delay. We hold a wake lock while - // debouncing the sensor. - mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED); - if (positive) { - mPendingProximity = PROXIMITY_POSITIVE; - setPendingProximityDebounceTime( - time + PROXIMITY_SENSOR_POSITIVE_DEBOUNCE_DELAY); // acquire wake lock - } else { - mPendingProximity = PROXIMITY_NEGATIVE; - setPendingProximityDebounceTime( - time + PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY); // acquire wake lock - } - - // Debounce the new sensor reading. - debounceProximitySensor(); - } - } - - private void debounceProximitySensor() { - if (mProximitySensorEnabled - && mPendingProximity != PROXIMITY_UNKNOWN - && mPendingProximityDebounceTime >= 0) { - final long now = mClock.uptimeMillis(); - if (mPendingProximityDebounceTime <= now) { - if (mProximity != mPendingProximity) { - // if the status of the sensor changed, stop ignoring. - mIgnoreProximityUntilChanged = false; - Slog.i(mTag, "No longer ignoring proximity [" + mPendingProximity + "]"); - } - // Sensor reading accepted. Apply the change then release the wake lock. - mProximity = mPendingProximity; - updatePowerState(); - clearPendingProximityDebounceTime(); // release wake lock (must be last) - } else { - // Need to wait a little longer. - // Debounce again later. We continue holding a wake lock while waiting. - Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED); - mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime); - } - } - } - - private void clearPendingProximityDebounceTime() { - if (mPendingProximityDebounceTime >= 0) { - mPendingProximityDebounceTime = -1; - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxDebounce); - } - } - - private void setPendingProximityDebounceTime(long debounceTime) { - if (mPendingProximityDebounceTime < 0) { - mCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxDebounce); - } - mPendingProximityDebounceTime = debounceTime; - } - private void sendOnStateChangedWithWakelock() { - if (!mOnStateChangedPending) { - mOnStateChangedPending = true; - mCallbacks.acquireSuspendBlocker(mSuspendBlockerIdOnStateChanged); - mHandler.post(mOnStateChangedRunnable); + boolean wakeLockAcquired = mWakelockController.acquireWakelock( + WakelockController.WAKE_LOCK_STATE_CHANGED); + if (wakeLockAcquired) { + mHandler.post(mWakelockController.getOnStateChangedRunnable()); } } @@ -2762,12 +2395,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } private void handleSettingsChange(boolean userSwitch) { - mPendingScreenBrightnessSetting = getScreenBrightnessSetting(); - mPendingAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); + mDisplayBrightnessController + .setPendingScreenBrightness(mDisplayBrightnessController + .getScreenBrightnessSetting()); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(userSwitch); if (userSwitch) { // Don't treat user switches as user initiated change. - setCurrentScreenBrightness(mPendingScreenBrightnessSetting); - updateAutoBrightnessAdjustment(); + mDisplayBrightnessController + .setAndNotifyCurrentScreenBrightness(mDisplayBrightnessController + .getPendingScreenBrightness()); if (mAutomaticBrightnessController != null) { mAutomaticBrightnessController.resetShortTermModel(); } @@ -2781,129 +2417,59 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); mHandler.postAtTime(() -> { - mUseAutoBrightness = screenBrightnessModeSetting - == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; + mAutomaticBrightnessStrategy.setUseAutoBrightness(screenBrightnessModeSetting + == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); updatePowerState(); }, mClock.uptimeMillis()); } - private float getAutoBrightnessAdjustmentSetting() { - final float adj = Settings.System.getFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f, UserHandle.USER_CURRENT); - return Float.isNaN(adj) ? 0.0f : clampAutoBrightnessAdjustment(adj); - } @Override public float getScreenBrightnessSetting() { - float brightness = mBrightnessSetting.getBrightness(); - if (Float.isNaN(brightness)) { - brightness = mScreenBrightnessDefault; - } - return clampAbsoluteBrightness(brightness); - } - - private void loadNitBasedBrightnessSetting() { - if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) { - float brightnessNitsForDefaultDisplay = - mBrightnessSetting.getBrightnessNitsForDefaultDisplay(); - if (brightnessNitsForDefaultDisplay >= 0) { - float brightnessForDefaultDisplay = getBrightnessFromNits( - brightnessNitsForDefaultDisplay); - if (isValidBrightnessValue(brightnessForDefaultDisplay)) { - mBrightnessSetting.setBrightness(brightnessForDefaultDisplay); - mCurrentScreenBrightnessSetting = brightnessForDefaultDisplay; - return; - } - } - } - mCurrentScreenBrightnessSetting = getScreenBrightnessSetting(); + return mDisplayBrightnessController.getScreenBrightnessSetting(); } @Override public void setBrightness(float brightnessValue, int userSerial) { - // Update the setting, which will eventually call back into DPC to have us actually update - // the display with the new value. - float clampedBrightnessValue = clampScreenBrightness(brightnessValue); - mBrightnessSetting.setUserSerial(userSerial); - mBrightnessSetting.setBrightness(clampedBrightnessValue); - if (mDisplayId == Display.DEFAULT_DISPLAY && mPersistBrightnessNitsForDefaultDisplay) { - float nits = convertToNits(clampedBrightnessValue); - if (nits >= 0) { - mBrightnessSetting.setBrightnessNitsForDefaultDisplay(nits); - } - } + mDisplayBrightnessController.setBrightness(clampScreenBrightness(brightnessValue), + userSerial); } @Override - public void onBootCompleted() { - Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - - private void updateScreenBrightnessSetting(float brightnessValue) { - if (!isValidBrightnessValue(brightnessValue) - || brightnessValue == mCurrentScreenBrightnessSetting) { - return; - } - setCurrentScreenBrightness(brightnessValue); - setBrightness(brightnessValue); - } - - private void setCurrentScreenBrightness(float brightnessValue) { - if (brightnessValue != mCurrentScreenBrightnessSetting) { - mCurrentScreenBrightnessSetting = brightnessValue; - postBrightnessChangeRunnable(); - } - } - - private void putAutoBrightnessAdjustmentSetting(float adjustment) { - if (mDisplayId == Display.DEFAULT_DISPLAY) { - mAutoBrightnessAdjustment = adjustment; - Settings.System.putFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adjustment, - UserHandle.USER_CURRENT); - } + public int getDisplayId() { + return mDisplayId; } - private boolean updateAutoBrightnessAdjustment() { - if (Float.isNaN(mPendingAutoBrightnessAdjustment)) { - return false; - } - if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) { - mPendingAutoBrightnessAdjustment = Float.NaN; - return false; - } - mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment; - mPendingAutoBrightnessAdjustment = Float.NaN; - mTemporaryAutoBrightnessAdjustment = Float.NaN; - return true; + @Override + public int getLeadDisplayId() { + return mLeadDisplayId; } - // We want to return true if the user has set the screen brightness. - // RBC on, off, and intensity changes will return false. - // Slider interactions whilst in RBC will return true, just as when in non-rbc. - private boolean updateUserSetScreenBrightness() { - if ((Float.isNaN(mPendingScreenBrightnessSetting) - || mPendingScreenBrightnessSetting < 0.0f)) { - return false; - } - if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) { - mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - return false; + @Override + public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux, + boolean slowChange) { + mBrightnessRangeController.onAmbientLuxChange(ambientLux); + if (nits == BrightnessMappingStrategy.INVALID_NITS) { + mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, slowChange); + } else { + float brightness = mDisplayBrightnessController.getBrightnessFromNits(nits); + if (BrightnessUtils.isValidBrightnessValue(brightness)) { + mDisplayBrightnessController.setBrightnessToFollow(brightness, slowChange); + } else { + // The device does not support nits + mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, + slowChange); + } } - setCurrentScreenBrightness(mPendingScreenBrightnessSetting); - mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting; - mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT; - mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; - return true; + sendUpdatePowerState(); } private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated, boolean wasShortTermModelActive, boolean autobrightnessEnabled, - boolean brightnessIsTemporary) { - final float brightnessInNits = convertToAdjustedNits(brightness); + boolean brightnessIsTemporary, boolean shouldUseAutoBrightness) { + final float brightnessInNits = + mDisplayBrightnessController.convertToAdjustedNits(brightness); // Don't report brightness to brightnessTracker: // If brightness is temporary (ie the slider has not been released) // or if we are in idle screen brightness mode. @@ -2915,12 +2481,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call || mAutomaticBrightnessController.isInIdleMode() || !autobrightnessEnabled || mBrightnessTracker == null - || !mUseAutoBrightness + || !shouldUseAutoBrightness || brightnessInNits < 0.0f) { return; } - if (userInitiated && !mAutomaticBrightnessController.hasValidAmbientLux()) { + if (userInitiated && (mAutomaticBrightnessController == null + || !mAutomaticBrightnessController.hasValidAmbientLux())) { // If we don't have a valid lux reading we can't report a valid // slider event so notify as if the system changed the brightness. userInitiated = false; @@ -2939,96 +2506,33 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessController.getLastSensorTimestamps()); } - private float convertToNits(float brightness) { - if (mAutomaticBrightnessController == null) { - return BrightnessMappingStrategy.INVALID_NITS; - } - return mAutomaticBrightnessController.convertToNits(brightness); - } - - private float convertToAdjustedNits(float brightness) { - if (mAutomaticBrightnessController == null) { - return BrightnessMappingStrategy.INVALID_NITS; + @Override + public void addDisplayBrightnessFollower(DisplayPowerControllerInterface follower) { + synchronized (mLock) { + mDisplayBrightnessFollowers.append(follower.getDisplayId(), follower); + sendUpdatePowerStateLocked(); } - return mAutomaticBrightnessController.convertToAdjustedNits(brightness); } - private float getBrightnessFromNits(float nits) { - if (mAutomaticBrightnessController == null) { - return PowerManager.BRIGHTNESS_INVALID_FLOAT; + @Override + public void removeDisplayBrightnessFollower(DisplayPowerControllerInterface follower) { + synchronized (mLock) { + mDisplayBrightnessFollowers.remove(follower.getDisplayId()); + mHandler.postAtTime(() -> follower.setBrightnessToFollow( + PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, + /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); } - return mAutomaticBrightnessController.getBrightnessFromNits(nits); } @GuardedBy("mLock") - private void updatePendingProximityRequestsLocked() { - mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked; - mPendingWaitForNegativeProximityLocked = false; - - if (mIgnoreProximityUntilChanged) { - // Also, lets stop waiting for negative proximity if we're ignoring it. - mWaitingForNegativeProximity = false; - } - } - - private void ignoreProximitySensorUntilChangedInternal() { - if (!mIgnoreProximityUntilChanged - && mProximity == PROXIMITY_POSITIVE) { - // Only ignore if it is still reporting positive (near) - mIgnoreProximityUntilChanged = true; - Slog.i(mTag, "Ignoring proximity"); - updatePowerState(); - } - } - - private final Runnable mOnStateChangedRunnable = new Runnable() { - @Override - public void run() { - mOnStateChangedPending = false; - mCallbacks.onStateChanged(); - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdOnStateChanged); - } - }; - - private void sendOnProximityPositiveWithWakelock() { - mCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxPositive); - mHandler.post(mOnProximityPositiveRunnable); - mOnProximityPositiveMessages++; - } - - private final Runnable mOnProximityPositiveRunnable = new Runnable() { - @Override - public void run() { - mOnProximityPositiveMessages--; - mCallbacks.onProximityPositive(); - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxPositive); - } - }; - - private void sendOnProximityNegativeWithWakelock() { - mOnProximityNegativeMessages++; - mCallbacks.acquireSuspendBlocker(mSuspendBlockerIdProxNegative); - mHandler.post(mOnProximityNegativeRunnable); - } - - private final Runnable mOnProximityNegativeRunnable = new Runnable() { - @Override - public void run() { - mOnProximityNegativeMessages--; - mCallbacks.onProximityNegative(); - mCallbacks.releaseSuspendBlocker(mSuspendBlockerIdProxNegative); + private void clearDisplayBrightnessFollowersLocked() { + for (int i = 0; i < mDisplayBrightnessFollowers.size(); i++) { + DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i); + mHandler.postAtTime(() -> follower.setBrightnessToFollow( + PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, + /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); } - }; - - /** - * Indicates whether the display state is ready to update. If this is the default display, we - * want to update it right away so that we can draw the boot animation on it. If it is not - * the default display, drawing the boot animation on it would look incorrect, so we need - * to wait until boot is completed. - * @return True if the display state is ready to update - */ - private boolean readyToUpdateDisplayState() { - return mDisplayId == Display.DEFAULT_DISPLAY || mBootCompleted; + mDisplayBrightnessFollowers.clear(); } @Override @@ -3040,31 +2544,23 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mLeadDisplayId=" + mLeadDisplayId); pw.println(" mLightSensor=" + mLightSensor); pw.println(" mDisplayBrightnessFollowers=" + mDisplayBrightnessFollowers); - pw.println(" mDozeStateOverride=" + mDozeStateOverride); pw.println(); pw.println("Display Power Controller Locked State:"); pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked); - pw.println(" mPendingWaitForNegativeProximityLocked=" - + mPendingWaitForNegativeProximityLocked); pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked); } pw.println(); pw.println("Display Power Controller Configuration:"); - pw.println(" mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault); pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig); - pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig); pw.println(" mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig); - pw.println(" mAllowAutoBrightnessWhileDozingConfig=" - + mAllowAutoBrightnessWhileDozingConfig); - pw.println(" mPersistBrightnessNitsForDefaultDisplay=" - + mPersistBrightnessNitsForDefaultDisplay); pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp); pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig); pw.println(" mColorFadeEnabled=" + mColorFadeEnabled); + pw.println(" mIsDisplayInternal=" + mIsDisplayInternal); synchronized (mCachedBrightnessInfo) { pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness.value); @@ -3082,7 +2578,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); - mHandler.runWithScissors(() -> dumpLocal(pw), 1000); } @@ -3090,35 +2585,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(); pw.println("Display Power Controller Thread State:"); pw.println(" mPowerRequest=" + mPowerRequest); - pw.println(" mUnfinishedBusiness=" + mUnfinishedBusiness); - pw.println(" mWaitingForNegativeProximity=" + mWaitingForNegativeProximity); - pw.println(" mProximitySensor=" + mProximitySensor); - pw.println(" mProximitySensorEnabled=" + mProximitySensorEnabled); - pw.println(" mProximityThreshold=" + mProximityThreshold); - pw.println(" mProximity=" + proximityToString(mProximity)); - pw.println(" mPendingProximity=" + proximityToString(mPendingProximity)); - pw.println(" mPendingProximityDebounceTime=" - + TimeUtils.formatUptime(mPendingProximityDebounceTime)); - pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity); - pw.println(" mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness); - pw.println(" mPendingScreenBrightnessSetting=" - + mPendingScreenBrightnessSetting); - pw.println(" mTemporaryScreenBrightness=" + mTemporaryScreenBrightness); - pw.println(" mBrightnessToFollow=" + mBrightnessToFollow); - pw.println(" mBrightnessToFollowSlowChange=" + mBrightnessToFollowSlowChange); - pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment); pw.println(" mBrightnessReason=" + mBrightnessReason); - pw.println(" mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment); - pw.println(" mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment); - pw.println(" mAppliedAutoBrightness=" + mAppliedAutoBrightness); pw.println(" mAppliedDimming=" + mAppliedDimming); - pw.println(" mAppliedLowPower=" + mAppliedLowPower); pw.println(" mAppliedThrottling=" + mAppliedThrottling); - pw.println(" mAppliedScreenBrightnessOverride=" + mAppliedScreenBrightnessOverride); - pw.println(" mAppliedTemporaryBrightness=" + mAppliedTemporaryBrightness); - pw.println(" mAppliedTemporaryAutoBrightnessAdjustment=" - + mAppliedTemporaryAutoBrightnessAdjustment); - pw.println(" mAppliedBrightnessBoost=" + mAppliedBrightnessBoost); pw.println(" mDozing=" + mDozing); pw.println(" mSkipRampState=" + skipRampStateToString(mSkipRampState)); pw.println(" mScreenOnBlockStartRealTime=" + mScreenOnBlockStartRealTime); @@ -3129,9 +2598,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call pw.println(" mReportedToPolicy=" + reportedToPolicyToString(mReportedScreenStateToPolicy)); pw.println(" mIsRbcActive=" + mIsRbcActive); - pw.println(" mOnStateChangePending=" + mOnStateChangedPending); - pw.println(" mOnProximityPositiveMessages=" + mOnProximityPositiveMessages); - pw.println(" mOnProximityNegativeMessages=" + mOnProximityNegativeMessages); + IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); + mAutomaticBrightnessStrategy.dump(ipw); if (mScreenBrightnessRampAnimator != null) { pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" @@ -3156,6 +2624,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call dumpBrightnessEvents(pw); } + dumpRbcEvents(pw); + if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.dump(pw); } @@ -3173,21 +2643,30 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayWhiteBalanceController.dump(pw); mDisplayWhiteBalanceSettings.dump(pw); } - } - private static String proximityToString(int state) { - switch (state) { - case PROXIMITY_UNKNOWN: - return "Unknown"; - case PROXIMITY_NEGATIVE: - return "Negative"; - case PROXIMITY_POSITIVE: - return "Positive"; - default: - return Integer.toString(state); + pw.println(); + + if (mWakelockController != null) { + mWakelockController.dumpLocal(pw); + } + + pw.println(); + if (mDisplayBrightnessController != null) { + mDisplayBrightnessController.dump(pw); + } + + pw.println(); + if (mDisplayStateController != null) { + mDisplayStateController.dumpsys(pw); + } + + pw.println(); + if (mBrightnessClamperController != null) { + mBrightnessClamperController.dump(ipw); } } + private static String reportedToPolicyToString(int state) { switch (state) { case REPORTED_TO_POLICY_SCREEN_OFF: @@ -3228,15 +2707,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } - private static float clampAbsoluteBrightness(float value) { - return MathUtils.constrain(value, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX); - } + private void dumpRbcEvents(PrintWriter pw) { + int size = mRbcEventRingBuffer.size(); + if (size < 1) { + pw.println("No Reduce Bright Colors Adjustments"); + return; + } - private static float clampAutoBrightnessAdjustment(float value) { - return MathUtils.constrain(value, -1.0f, 1.0f); + pw.println("Reduce Bright Colors Adjustments Last " + size + " Events: "); + BrightnessEvent[] eventArray = mRbcEventRingBuffer.toArray(); + for (int i = 0; i < mRbcEventRingBuffer.size(); i++) { + pw.println(" " + eventArray[i]); + } } + private void noteScreenState(int screenState) { // Log screen state change with display id FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED_V2, @@ -3363,20 +2848,21 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // It's easier to check if the brightness is at maximum level using the brightness // value untouched by any modifiers boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax(); - float brightnessInNits = convertToAdjustedNits(event.getBrightness()); + float brightnessInNits = + mDisplayBrightnessController.convertToAdjustedNits(event.getBrightness()); float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f; int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1; float appliedHbmMaxNits = event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF - ? -1f : convertToAdjustedNits(event.getHbmMax()); + ? -1f : mDisplayBrightnessController.convertToAdjustedNits(event.getHbmMax()); // thermalCapNits set to -1 if not currently capping max brightness float appliedThermalCapNits = event.getThermalMax() == PowerManager.BRIGHTNESS_MAX - ? -1f : convertToAdjustedNits(event.getThermalMax()); - + ? -1f : mDisplayBrightnessController.convertToAdjustedNits(event.getThermalMax()); if (mIsDisplayInternal) { FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED, - convertToAdjustedNits(event.getInitialBrightness()), + mDisplayBrightnessController + .convertToAdjustedNits(event.getInitialBrightness()), brightnessInNits, event.getLux(), event.getPhysicalDisplayId(), @@ -3393,7 +2879,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0, - mBrightnessThrottler.getBrightnessMaxReason(), + mBrightnessClamperController.getBrightnessMaxReason(), + // TODO: (flc) add brightnessMinReason here too. (modifier & BrightnessReason.MODIFIER_DIMMED) > 0, event.isRbcEnabled(), (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0, @@ -3404,6 +2891,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } } + /** + * Indicates whether the display state is ready to update. If this is the default display, we + * want to update it right away so that we can draw the boot animation on it. If it is not + * the default display, drawing the boot animation on it would look incorrect, so we need + * to wait until boot is completed. + * @return True if the display state is ready to update + */ + private boolean readyToUpdateDisplayState() { + return mDisplayId == Display.DEFAULT_DISPLAY || mBootCompleted; + } + private final class DisplayControllerHandler extends Handler { DisplayControllerHandler(Looper looper) { super(looper, null, true /*async*/); @@ -3416,10 +2914,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call updatePowerState(); break; - case MSG_PROXIMITY_SENSOR_DEBOUNCED: - debounceProximitySensor(); - break; - case MSG_SCREEN_ON_UNBLOCKED: if (mPendingScreenOnUnblocker == msg.obj) { unblockScreenOn(); @@ -3432,27 +2926,38 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call updatePowerState(); } break; + case MSG_OFFLOADING_SCREEN_ON_UNBLOCKED: + if (mDisplayOffloadSession == msg.obj) { + unblockScreenOnByDisplayOffload(); + updatePowerState(); + } + break; case MSG_CONFIGURE_BRIGHTNESS: - mBrightnessConfiguration = (BrightnessConfiguration) msg.obj; - mShouldResetShortTermModel = msg.arg1 == 1; + BrightnessConfiguration brightnessConfiguration = + (BrightnessConfiguration) msg.obj; + mAutomaticBrightnessStrategy.setBrightnessConfiguration(brightnessConfiguration, + msg.arg1 == 1); + if (mBrightnessTracker != null) { + mBrightnessTracker + .setShouldCollectColorSample(brightnessConfiguration != null + && brightnessConfiguration.shouldCollectColorSamples()); + } updatePowerState(); break; case MSG_SET_TEMPORARY_BRIGHTNESS: // TODO: Should we have a a timeout for the temporary brightness? - mTemporaryScreenBrightness = Float.intBitsToFloat(msg.arg1); + mDisplayBrightnessController + .setTemporaryBrightness(Float.intBitsToFloat(msg.arg1)); updatePowerState(); break; case MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT: - mTemporaryAutoBrightnessAdjustment = Float.intBitsToFloat(msg.arg1); + mAutomaticBrightnessStrategy + .setTemporaryAutoBrightnessAdjustment(Float.intBitsToFloat(msg.arg1)); updatePowerState(); break; - case MSG_IGNORE_PROXIMITY: - ignoreProximitySensorUntilChangedInternal(); - break; - case MSG_STOP: cleanupHandlerThreadAfterStop(); break; @@ -3500,27 +3005,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call case MSG_SET_DWBC_LOGGING_ENABLED: setDwbcLoggingEnabled(msg.arg1); break; + case MSG_SET_BRIGHTNESS_FROM_OFFLOAD: + mDisplayBrightnessController.setBrightnessFromOffload( + Float.intBitsToFloat(msg.arg1)); + updatePowerState(); + break; } } } - private final SensorEventListener mProximitySensorListener = new SensorEventListener() { - @Override - public void onSensorChanged(SensorEvent event) { - if (mProximitySensorEnabled) { - final long time = mClock.uptimeMillis(); - final float distance = event.values[0]; - boolean positive = distance >= 0.0f && distance < mProximityThreshold; - handleProximitySensorEvent(time, positive); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - // Not used. - } - }; - private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler) { @@ -3531,6 +3024,16 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call public void onChange(boolean selfChange, Uri uri) { if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE))) { handleBrightnessModeChange(); + } else if (uri.equals(Settings.System.getUriFor( + Settings.System.SCREEN_BRIGHTNESS_FOR_ALS))) { + int preset = Settings.System.getIntForUser(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, + Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, + UserHandle.USER_CURRENT); + Slog.i(mTag, "Setting up auto-brightness for preset " + + autoBrightnessPresetToString(preset)); + setUpAutoBrightness(mContext, mHandler); + sendUpdatePowerState(); } else { handleSettingsChange(false /* userSwitch */); } @@ -3581,28 +3084,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call msg.sendToTarget(); } - @VisibleForTesting - String getSuspendBlockerUnfinishedBusinessId(int displayId) { - return "[" + displayId + "]unfinished business"; - } - - String getSuspendBlockerOnStateChangedId(int displayId) { - return "[" + displayId + "]on state changed"; - } - - String getSuspendBlockerProxPositiveId(int displayId) { - return "[" + displayId + "]prox positive"; - } - - String getSuspendBlockerProxNegativeId(int displayId) { - return "[" + displayId + "]prox negative"; - } - - @VisibleForTesting - String getSuspendBlockerProxDebounceId(int displayId) { - return "[" + displayId + "]prox debounce"; - } - /** Functional interface for providing time. */ @VisibleForTesting interface Clock { @@ -3629,6 +3110,20 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call return new DualRampAnimator(dps, firstProperty, secondProperty); } + WakelockController getWakelockController(int displayId, + DisplayPowerCallbacks displayPowerCallbacks) { + return new WakelockController(displayId, displayPowerCallbacks); + } + + DisplayPowerProximityStateController getDisplayPowerProximityStateController( + WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, + Looper looper, Runnable nudgeUpdatePowerState, + int displayId, SensorManager sensorManager) { + return new DisplayPowerProximityStateController(wakelockController, displayDeviceConfig, + looper, nudgeUpdatePowerState, + displayId, sensorManager, /* injector= */ null); + } + AutomaticBrightnessController getAutomaticBrightnessController( AutomaticBrightnessController.Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, @@ -3711,11 +3206,32 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call hbmChangeCallback, hbmMetadata, context); } + BrightnessRangeController getBrightnessRangeController( + HighBrightnessModeController hbmController, Runnable modeChangeCallback, + DisplayDeviceConfig displayDeviceConfig, Handler handler, + DisplayManagerFlags flags, IBinder displayToken, DisplayDeviceInfo info) { + return new BrightnessRangeController(hbmController, + modeChangeCallback, displayDeviceConfig, handler, flags, displayToken, info); + } + + BrightnessClamperController getBrightnessClamperController(Handler handler, + BrightnessClamperController.ClamperChangeListener clamperChangeListener, + BrightnessClamperController.DisplayDeviceData data, Context context, + DisplayManagerFlags flags) { + + return new BrightnessClamperController(handler, clamperChangeListener, data, context, + flags); + } + DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, SensorManager sensorManager, Resources resources) { return DisplayWhiteBalanceFactory.create(handler, sensorManager, resources); } + + boolean isColorFadeEnabled() { + return !ActivityManager.isLowRamDeviceStatic(); + } } static class CachedBrightnessInfo { diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java deleted file mode 100644 index 2d860c0cc673..000000000000 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ /dev/null @@ -1,3267 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.display; - -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; -import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessPresetToString; - -import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.annotation.Nullable; -import android.annotation.SuppressLint; -import android.annotation.UserIdInt; -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.ParceledListSlice; -import android.content.res.Resources; -import android.database.ContentObserver; -import android.hardware.Sensor; -import android.hardware.SensorManager; -import android.hardware.display.AmbientBrightnessDayStats; -import android.hardware.display.BrightnessChangeEvent; -import android.hardware.display.BrightnessConfiguration; -import android.hardware.display.BrightnessInfo; -import android.hardware.display.DisplayManagerInternal; -import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; -import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; -import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; -import android.metrics.LogMaker; -import android.net.Uri; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.Trace; -import android.os.UserHandle; -import android.provider.Settings; -import android.util.FloatProperty; -import android.util.IndentingPrintWriter; -import android.util.MathUtils; -import android.util.MutableFloat; -import android.util.MutableInt; -import android.util.Slog; -import android.util.SparseArray; -import android.view.Display; - -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.display.BrightnessSynchronizer; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.internal.util.FrameworkStatsLog; -import com.android.internal.util.RingBuffer; -import com.android.server.LocalServices; -import com.android.server.am.BatteryStatsService; -import com.android.server.display.RampAnimator.DualRampAnimator; -import com.android.server.display.brightness.BrightnessEvent; -import com.android.server.display.brightness.BrightnessReason; -import com.android.server.display.brightness.BrightnessUtils; -import com.android.server.display.brightness.DisplayBrightnessController; -import com.android.server.display.brightness.clamper.BrightnessClamperController; -import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy; -import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal; -import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; -import com.android.server.display.feature.DisplayManagerFlags; -import com.android.server.display.layout.Layout; -import com.android.server.display.state.DisplayStateController; -import com.android.server.display.utils.DebugUtils; -import com.android.server.display.utils.SensorUtils; -import com.android.server.display.whitebalance.DisplayWhiteBalanceController; -import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory; -import com.android.server.display.whitebalance.DisplayWhiteBalanceSettings; -import com.android.server.policy.WindowManagerPolicy; - -import java.io.PrintWriter; -import java.util.Objects; - -/** - * Controls the power state of the display. - * - * Handles the proximity sensor, light sensor, and animations between states - * including the screen off animation. - * - * This component acts independently of the rest of the power manager service. - * In particular, it does not share any state and it only communicates - * via asynchronous callbacks to inform the power manager that something has - * changed. - * - * Everything this class does internally is serialized on its handler although - * it may be accessed by other threads from the outside. - * - * Note that the power manager service guarantees that it will hold a suspend - * blocker as long as the display is not ready. So most of the work done here - * does not need to worry about holding a suspend blocker unless it happens - * independently of the display ready signal. - * - * For debugging, you can make the color fade and brightness animations run - * slower by changing the "animator duration scale" option in Development Settings. - */ -final class DisplayPowerController2 implements AutomaticBrightnessController.Callbacks, - DisplayWhiteBalanceController.Callbacks, DisplayPowerControllerInterface { - private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked"; - private static final String SCREEN_OFF_BLOCKED_TRACE_NAME = "Screen off blocked"; - - private static final String TAG = "DisplayPowerController2"; - // To enable these logs, run: - // 'adb shell setprop persist.log.tag.DisplayPowerController2 DEBUG && adb reboot' - private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); - private static final String SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME = - "Screen on blocked by displayoffload"; - - // If true, uses the color fade on animation. - // We might want to turn this off if we cannot get a guarantee that the screen - // actually turns on and starts showing new content after the call to set the - // screen state returns. Playing the animation can also be somewhat slow. - private static final boolean USE_COLOR_FADE_ON_ANIMATION = false; - - private static final float SCREEN_ANIMATION_RATE_MINIMUM = 0.0f; - - private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250; - private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 400; - - private static final int MSG_UPDATE_POWER_STATE = 1; - private static final int MSG_SCREEN_ON_UNBLOCKED = 2; - private static final int MSG_SCREEN_OFF_UNBLOCKED = 3; - private static final int MSG_CONFIGURE_BRIGHTNESS = 4; - private static final int MSG_SET_TEMPORARY_BRIGHTNESS = 5; - private static final int MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT = 6; - private static final int MSG_STOP = 7; - private static final int MSG_UPDATE_BRIGHTNESS = 8; - private static final int MSG_UPDATE_RBC = 9; - private static final int MSG_BRIGHTNESS_RAMP_DONE = 10; - private static final int MSG_STATSD_HBM_BRIGHTNESS = 11; - private static final int MSG_SWITCH_USER = 12; - private static final int MSG_BOOT_COMPLETED = 13; - private static final int MSG_SET_DWBC_STRONG_MODE = 14; - private static final int MSG_SET_DWBC_COLOR_OVERRIDE = 15; - private static final int MSG_SET_DWBC_LOGGING_ENABLED = 16; - private static final int MSG_SET_BRIGHTNESS_FROM_OFFLOAD = 17; - private static final int MSG_OFFLOADING_SCREEN_ON_UNBLOCKED = 18; - - - - private static final int BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS = 500; - - - // State machine constants for tracking initial brightness ramp skipping when enabled. - private static final int RAMP_STATE_SKIP_NONE = 0; - private static final int RAMP_STATE_SKIP_INITIAL = 1; - private static final int RAMP_STATE_SKIP_AUTOBRIGHT = 2; - - private static final int REPORTED_TO_POLICY_UNREPORTED = -1; - private static final int REPORTED_TO_POLICY_SCREEN_OFF = 0; - private static final int REPORTED_TO_POLICY_SCREEN_TURNING_ON = 1; - private static final int REPORTED_TO_POLICY_SCREEN_ON = 2; - private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3; - - private static final int RINGBUFFER_MAX = 100; - private static final int RINGBUFFER_RBC_MAX = 20; - - private static final float[] BRIGHTNESS_RANGE_BOUNDARIES = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, - 90, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1200, - 1400, 1600, 1800, 2000, 2250, 2500, 2750, 3000}; - private static final int[] BRIGHTNESS_RANGE_INDEX = { - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_UNKNOWN, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_0_1, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1_2, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2_3, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3_4, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_4_5, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_5_6, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_6_7, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_7_8, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_8_9, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_9_10, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_10_20, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_20_30, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_30_40, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_40_50, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_50_60, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_60_70, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_70_80, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_80_90, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_90_100, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_100_200, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_200_300, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_300_400, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_400_500, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_500_600, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_600_700, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_700_800, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_800_900, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_900_1000, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1000_1200, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1200_1400, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1400_1600, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1600_1800, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_1800_2000, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2000_2250, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2250_2500, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2500_2750, - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_2750_3000, - }; - - private final String mTag; - - private final Object mLock = new Object(); - - private final Context mContext; - - // Our handler. - private final DisplayControllerHandler mHandler; - - // Battery stats. - @Nullable - private final IBatteryStats mBatteryStats; - - // The sensor manager. - private final SensorManager mSensorManager; - - // The window manager policy. - private final WindowManagerPolicy mWindowManagerPolicy; - - // The display blanker. - private final DisplayBlanker mBlanker; - - // The LogicalDisplay tied to this DisplayPowerController2. - private final LogicalDisplay mLogicalDisplay; - - // The ID of the LogicalDisplay tied to this DisplayPowerController2. - private final int mDisplayId; - - // The ID of the display which this display follows for brightness purposes. - private int mLeadDisplayId = Layout.NO_LEAD_DISPLAY; - - // The unique ID of the primary display device currently tied to this logical display - private String mUniqueDisplayId; - - // Tracker for brightness changes. - @Nullable - private final BrightnessTracker mBrightnessTracker; - - // Tracker for brightness settings changes. - private final SettingsObserver mSettingsObserver; - - // The doze screen brightness. - private final float mScreenBrightnessDozeConfig; - - // True if auto-brightness should be used. - private boolean mUseSoftwareAutoBrightnessConfig; - - // Whether or not the color fade on screen on / off is enabled. - private final boolean mColorFadeEnabled; - - @GuardedBy("mCachedBrightnessInfo") - private final CachedBrightnessInfo mCachedBrightnessInfo = new CachedBrightnessInfo(); - - private DisplayDevice mDisplayDevice; - - // True if we should fade the screen while turning it off, false if we should play - // a stylish color fade animation instead. - private final boolean mColorFadeFadesConfig; - - // True if we need to fake a transition to off when coming out of a doze state. - // Some display hardware will blank itself when coming out of doze in order to hide - // artifacts. For these displays we fake a transition into OFF so that policy can appropriately - // blank itself and begin an appropriate power on animation. - private final boolean mDisplayBlanksAfterDozeConfig; - - // True if there are only buckets of brightness values when the display is in the doze state, - // rather than a full range of values. If this is true, then we'll avoid animating the screen - // brightness since it'd likely be multiple jarring brightness transitions instead of just one - // to reach the final state. - private final boolean mBrightnessBucketsInDozeConfig; - - private final Clock mClock; - private final Injector mInjector; - - // Maximum time a ramp animation can take. - private long mBrightnessRampIncreaseMaxTimeMillis; - private long mBrightnessRampDecreaseMaxTimeMillis; - - // Maximum time a ramp animation can take in idle mode. - private long mBrightnessRampIncreaseMaxTimeIdleMillis; - private long mBrightnessRampDecreaseMaxTimeIdleMillis; - - // The pending power request. - // Initially null until the first call to requestPowerState. - @GuardedBy("mLock") - private DisplayPowerRequest mPendingRequestLocked; - - // True if the pending power request or wait for negative proximity flag - // has been changed since the last update occurred. - @GuardedBy("mLock") - private boolean mPendingRequestChangedLocked; - - // Set to true when the important parts of the pending power request have been applied. - // The important parts are mainly the screen state. Brightness changes may occur - // concurrently. - @GuardedBy("mLock") - private boolean mDisplayReadyLocked; - - // Set to true if a power state update is required. - @GuardedBy("mLock") - private boolean mPendingUpdatePowerStateLocked; - - /* The following state must only be accessed by the handler thread. */ - - // The currently requested power state. - // The power controller will progressively update its internal state to match - // the requested power state. Initially null until the first update. - private DisplayPowerRequest mPowerRequest; - - // The current power state. - // Must only be accessed on the handler thread. - private DisplayPowerState mPowerState; - - - - // The currently active screen on unblocker. This field is non-null whenever - // we are waiting for a callback to release it and unblock the screen. - private ScreenOnUnblocker mPendingScreenOnUnblocker; - private ScreenOffUnblocker mPendingScreenOffUnblocker; - private Runnable mPendingScreenOnUnblockerByDisplayOffload; - - // True if we were in the process of turning off the screen. - // This allows us to recover more gracefully from situations where we abort - // turning off the screen. - private boolean mPendingScreenOff; - - // The elapsed real time when the screen on was blocked. - private long mScreenOnBlockStartRealTime; - private long mScreenOffBlockStartRealTime; - private long mScreenOnBlockByDisplayOffloadStartRealTime; - - // Screen state we reported to policy. Must be one of REPORTED_TO_POLICY_* fields. - private int mReportedScreenStateToPolicy = REPORTED_TO_POLICY_UNREPORTED; - - // Used to deduplicate the displayoffload blocking screen on logic. One block per turning on. - // This value is reset when screen on is reported or the blocking is cancelled. - private boolean mScreenTurningOnWasBlockedByDisplayOffload; - - // If the last recorded screen state was dozing or not. - private boolean mDozing; - - private boolean mAppliedDimming; - - private boolean mAppliedThrottling; - - // Reason for which the brightness was last changed. See {@link BrightnessReason} for more - // information. - // At the time of this writing, this value is changed within updatePowerState() only, which is - // limited to the thread used by DisplayControllerHandler. - private final BrightnessReason mBrightnessReason = new BrightnessReason(); - private final BrightnessReason mBrightnessReasonTemp = new BrightnessReason(); - - // Brightness animation ramp rates in brightness units per second - private float mBrightnessRampRateFastDecrease; - private float mBrightnessRampRateFastIncrease; - private float mBrightnessRampRateSlowDecrease; - private float mBrightnessRampRateSlowIncrease; - private float mBrightnessRampRateSlowDecreaseIdle; - private float mBrightnessRampRateSlowIncreaseIdle; - - // Report HBM brightness change to StatsD - private int mDisplayStatsId; - private float mLastStatsBrightness = PowerManager.BRIGHTNESS_MIN; - - // Whether or not to skip the initial brightness ramps into STATE_ON. - private final boolean mSkipScreenOnBrightnessRamp; - - // Display white balance components. - // Critical methods must be called on DPC2 handler thread. - @Nullable - private final DisplayWhiteBalanceSettings mDisplayWhiteBalanceSettings; - @Nullable - private final DisplayWhiteBalanceController mDisplayWhiteBalanceController; - - @Nullable - private final ColorDisplayServiceInternal mCdsi; - private float[] mNitsRange; - - private final BrightnessRangeController mBrightnessRangeController; - - private final BrightnessThrottler mBrightnessThrottler; - - private final BrightnessClamperController mBrightnessClamperController; - - private final Runnable mOnBrightnessChangeRunnable; - - private final BrightnessEvent mLastBrightnessEvent; - private final BrightnessEvent mTempBrightnessEvent; - - private final DisplayBrightnessController mDisplayBrightnessController; - - // Keeps a record of brightness changes for dumpsys. - private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer; - - // Keeps a record of rbc changes for dumpsys. - private final RingBuffer<BrightnessEvent> mRbcEventRingBuffer = - new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_RBC_MAX); - - // Controls and tracks all the wakelocks that are acquired/released by the system. Also acts as - // a medium of communication between this class and the PowerManagerService. - private final WakelockController mWakelockController; - - // Tracks and manages the proximity state of the associated display. - private final DisplayPowerProximityStateController mDisplayPowerProximityStateController; - - // Tracks and manages the display state of the associated display. - private final DisplayStateController mDisplayStateController; - - - // Responsible for evaluating and tracking the automatic brightness relevant states. - // Todo: This is a temporary workaround. Ideally DPC2 should never talk to the strategies - private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy; - - // A record of state for skipping brightness ramps. - private int mSkipRampState = RAMP_STATE_SKIP_NONE; - - // The first autobrightness value set when entering RAMP_STATE_SKIP_INITIAL. - private float mInitialAutoBrightness; - - // The controller for the automatic brightness level. - @Nullable - private AutomaticBrightnessController mAutomaticBrightnessController; - - // The controller for the sensor used to estimate ambient lux while the display is off. - @Nullable - private ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; - - private Sensor mLightSensor; - private Sensor mScreenOffBrightnessSensor; - - private boolean mIsRbcActive; - - // Animators. - private ObjectAnimator mColorFadeOnAnimator; - private ObjectAnimator mColorFadeOffAnimator; - private DualRampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator; - - // True if this DisplayPowerController2 has been stopped and should no longer be running. - private boolean mStopped; - - private DisplayDeviceConfig mDisplayDeviceConfig; - - private boolean mIsEnabled; - private boolean mIsInTransition; - private boolean mIsDisplayInternal; - - // The id of the thermal brightness throttling policy that should be used. - private String mThermalBrightnessThrottlingDataId; - - // DPCs following the brightness of this DPC. This is used in concurrent displays mode - there - // is one lead display, the additional displays follow the brightness value of the lead display. - @GuardedBy("mLock") - private SparseArray<DisplayPowerControllerInterface> mDisplayBrightnessFollowers = - new SparseArray(); - - private boolean mBootCompleted; - private final DisplayManagerFlags mFlags; - - private DisplayOffloadSession mDisplayOffloadSession; - - /** - * Creates the display power controller. - */ - DisplayPowerController2(Context context, Injector injector, - DisplayPowerCallbacks callbacks, Handler handler, - SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay, - BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting, - Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata, - boolean bootCompleted, DisplayManagerFlags flags) { - mFlags = flags; - mInjector = injector != null ? injector : new Injector(); - mClock = mInjector.getClock(); - mLogicalDisplay = logicalDisplay; - mDisplayId = mLogicalDisplay.getDisplayIdLocked(); - mSensorManager = sensorManager; - mHandler = new DisplayControllerHandler(handler.getLooper()); - mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked() - .getDisplayDeviceConfig(); - mIsEnabled = logicalDisplay.isEnabledLocked(); - mIsInTransition = logicalDisplay.isInTransitionLocked(); - mIsDisplayInternal = logicalDisplay.getPrimaryDisplayDeviceLocked() - .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL; - mWakelockController = mInjector.getWakelockController(mDisplayId, callbacks); - mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController( - mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(), - () -> updatePowerState(), mDisplayId, mSensorManager); - mDisplayStateController = new DisplayStateController(mDisplayPowerProximityStateController); - mTag = TAG + "[" + mDisplayId + "]"; - mThermalBrightnessThrottlingDataId = - logicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId; - mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); - mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId(); - mDisplayStatsId = mUniqueDisplayId.hashCode(); - - mLastBrightnessEvent = new BrightnessEvent(mDisplayId); - mTempBrightnessEvent = new BrightnessEvent(mDisplayId); - - if (mDisplayId == Display.DEFAULT_DISPLAY) { - mBatteryStats = BatteryStatsService.getService(); - } else { - mBatteryStats = null; - } - - mSettingsObserver = new SettingsObserver(mHandler); - mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class); - mBlanker = blanker; - mContext = context; - mBrightnessTracker = brightnessTracker; - mOnBrightnessChangeRunnable = onBrightnessChangeRunnable; - - PowerManager pm = context.getSystemService(PowerManager.class); - - final Resources resources = context.getResources(); - - // DOZE AND DIM SETTINGS - mScreenBrightnessDozeConfig = BrightnessUtils.clampAbsoluteBrightness( - pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)); - loadBrightnessRampRates(); - mSkipScreenOnBrightnessRamp = resources.getBoolean( - R.bool.config_skipScreenOnBrightnessRamp); - - Runnable modeChangeCallback = () -> { - sendUpdatePowerState(); - postBrightnessChangeRunnable(); - // TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern. - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.update(); - } - }; - - HighBrightnessModeController hbmController = createHbmControllerLocked(hbmMetadata, - modeChangeCallback); - mBrightnessThrottler = createBrightnessThrottlerLocked(); - - mBrightnessRangeController = mInjector.getBrightnessRangeController(hbmController, - modeChangeCallback, mDisplayDeviceConfig, mHandler, flags, - mDisplayDevice.getDisplayTokenLocked(), - mDisplayDevice.getDisplayDeviceInfoLocked()); - - mDisplayBrightnessController = - new DisplayBrightnessController(context, null, - mDisplayId, mLogicalDisplay.getDisplayInfoLocked().brightnessDefault, - brightnessSetting, () -> postBrightnessChangeRunnable(), - new HandlerExecutor(mHandler), flags); - - mBrightnessClamperController = mInjector.getBrightnessClamperController( - mHandler, modeChangeCallback::run, - new BrightnessClamperController.DisplayDeviceData( - mUniqueDisplayId, - mThermalBrightnessThrottlingDataId, - logicalDisplay.getPowerThrottlingDataIdLocked(), - mDisplayDeviceConfig), mContext, flags); - // Seed the cached brightness - saveBrightnessInfo(getScreenBrightnessSetting()); - mAutomaticBrightnessStrategy = - mDisplayBrightnessController.getAutomaticBrightnessStrategy(); - - DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null; - DisplayWhiteBalanceController displayWhiteBalanceController = null; - if (mDisplayId == Display.DEFAULT_DISPLAY) { - try { - displayWhiteBalanceController = mInjector.getDisplayWhiteBalanceController( - mHandler, mSensorManager, resources); - displayWhiteBalanceSettings = new DisplayWhiteBalanceSettings(mContext, mHandler); - displayWhiteBalanceSettings.setCallbacks(this); - displayWhiteBalanceController.setCallbacks(this); - } catch (Exception e) { - Slog.e(mTag, "failed to set up display white-balance: " + e); - } - } - mDisplayWhiteBalanceSettings = displayWhiteBalanceSettings; - mDisplayWhiteBalanceController = displayWhiteBalanceController; - - loadNitsRange(resources); - - if (mDisplayId == Display.DEFAULT_DISPLAY) { - mCdsi = LocalServices.getService(ColorDisplayServiceInternal.class); - if (mCdsi != null) { - boolean active = mCdsi.setReduceBrightColorsListener( - new ReduceBrightColorsListener() { - @Override - public void onReduceBrightColorsActivationChanged(boolean activated, - boolean userInitiated) { - applyReduceBrightColorsSplineAdjustment(); - - } - - @Override - public void onReduceBrightColorsStrengthChanged(int strength) { - applyReduceBrightColorsSplineAdjustment(); - } - }); - if (active) { - applyReduceBrightColorsSplineAdjustment(); - } - } - } else { - mCdsi = null; - } - - setUpAutoBrightness(context, handler); - - mColorFadeEnabled = mInjector.isColorFadeEnabled() - && !resources.getBoolean( - com.android.internal.R.bool.config_displayColorFadeDisabled); - mColorFadeFadesConfig = resources.getBoolean( - R.bool.config_animateScreenLights); - - mDisplayBlanksAfterDozeConfig = resources.getBoolean( - R.bool.config_displayBlanksAfterDoze); - - mBrightnessBucketsInDozeConfig = resources.getBoolean( - R.bool.config_displayBrightnessBucketsInDoze); - - mBootCompleted = bootCompleted; - } - - private void applyReduceBrightColorsSplineAdjustment() { - mHandler.obtainMessage(MSG_UPDATE_RBC).sendToTarget(); - sendUpdatePowerState(); - } - - private void handleRbcChanged() { - if (mAutomaticBrightnessController == null) { - return; - } - - float[] adjustedNits = new float[mNitsRange.length]; - for (int i = 0; i < mNitsRange.length; i++) { - adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]); - } - mIsRbcActive = mCdsi.isReduceBrightColorsActivated(); - mAutomaticBrightnessController.recalculateSplines(mIsRbcActive, adjustedNits); - } - - /** - * Returns true if the proximity sensor screen-off function is available. - */ - @Override - public boolean isProximitySensorAvailable() { - return mDisplayPowerProximityStateController.isProximitySensorAvailable(); - } - - /** - * Get the {@link BrightnessChangeEvent}s for the specified user. - * - * @param userId userId to fetch data for - * @param includePackage if false will null out the package name in events - */ - @Nullable - @Override - public ParceledListSlice<BrightnessChangeEvent> getBrightnessEvents( - @UserIdInt int userId, boolean includePackage) { - if (mBrightnessTracker == null) { - return null; - } - return mBrightnessTracker.getEvents(userId, includePackage); - } - - @Override - public void onSwitchUser(@UserIdInt int newUserId) { - Message msg = mHandler.obtainMessage(MSG_SWITCH_USER, newUserId); - mHandler.sendMessage(msg); - } - - private void handleOnSwitchUser(@UserIdInt int newUserId) { - handleSettingsChange(true /* userSwitch */); - handleBrightnessModeChange(); - if (mBrightnessTracker != null) { - mBrightnessTracker.onSwitchUser(newUserId); - } - } - - @Nullable - @Override - public ParceledListSlice<AmbientBrightnessDayStats> getAmbientBrightnessStats( - @UserIdInt int userId) { - if (mBrightnessTracker == null) { - return null; - } - return mBrightnessTracker.getAmbientBrightnessStats(userId); - } - - /** - * Persist the brightness slider events and ambient brightness stats to disk. - */ - @Override - public void persistBrightnessTrackerState() { - if (mBrightnessTracker != null) { - mBrightnessTracker.persistBrightnessTrackerState(); - } - } - - /** - * Requests a new power state. - * The controller makes a copy of the provided object and then - * begins adjusting the power state to match what was requested. - * - * @param request The requested power state. - * @param waitForNegativeProximity If true, issues a request to wait for - * negative proximity before turning the screen back on, - * assuming the screen - * was turned off by the proximity sensor. - * @return True if display is ready, false if there are important changes that must - * be made asynchronously (such as turning the screen on), in which case the caller - * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()} - * then try the request again later until the state converges. - */ - public boolean requestPowerState(DisplayPowerRequest request, - boolean waitForNegativeProximity) { - if (DEBUG) { - Slog.d(mTag, "requestPowerState: " - + request + ", waitForNegativeProximity=" + waitForNegativeProximity); - } - - synchronized (mLock) { - if (mStopped) { - return true; - } - - boolean changed = mDisplayPowerProximityStateController - .setPendingWaitForNegativeProximityLocked(waitForNegativeProximity); - - if (mPendingRequestLocked == null) { - mPendingRequestLocked = new DisplayPowerRequest(request); - changed = true; - } else if (!mPendingRequestLocked.equals(request)) { - mPendingRequestLocked.copyFrom(request); - changed = true; - } - - if (changed) { - mDisplayReadyLocked = false; - if (!mPendingRequestChangedLocked) { - mPendingRequestChangedLocked = true; - sendUpdatePowerStateLocked(); - } - } - - return mDisplayReadyLocked; - } - } - - @Override - public void overrideDozeScreenState(int displayState) { - mHandler.postAtTime(() -> { - if (mDisplayOffloadSession == null - || !(DisplayOffloadSession.isSupportedOffloadState(displayState) - || displayState == Display.STATE_UNKNOWN)) { - return; - } - mDisplayStateController.overrideDozeScreenState(displayState); - sendUpdatePowerState(); - }, mClock.uptimeMillis()); - } - - @Override - public void setDisplayOffloadSession(DisplayOffloadSession session) { - if (session == mDisplayOffloadSession) { - return; - } - unblockScreenOnByDisplayOffload(); - mDisplayOffloadSession = session; - } - - @Override - public BrightnessConfiguration getDefaultBrightnessConfiguration() { - if (mAutomaticBrightnessController == null) { - return null; - } - return mAutomaticBrightnessController.getDefaultConfig(); - } - - /** - * Notified when the display is changed. We use this to apply any changes that might be needed - * when displays get swapped on foldable devices. For example, different brightness properties - * of each display need to be properly reflected in AutomaticBrightnessController. - * - * Make sure DisplayManagerService.mSyncRoot lock is held when this is called - */ - @Override - public void onDisplayChanged(HighBrightnessModeMetadata hbmMetadata, int leadDisplayId) { - mLeadDisplayId = leadDisplayId; - final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); - if (device == null) { - Slog.wtf(mTag, "Display Device is null in DisplayPowerController2 for display: " - + mLogicalDisplay.getDisplayIdLocked()); - return; - } - - final String uniqueId = device.getUniqueId(); - final DisplayDeviceConfig config = device.getDisplayDeviceConfig(); - final IBinder token = device.getDisplayTokenLocked(); - final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); - final boolean isEnabled = mLogicalDisplay.isEnabledLocked(); - final boolean isInTransition = mLogicalDisplay.isInTransitionLocked(); - final boolean isDisplayInternal = mLogicalDisplay.getPrimaryDisplayDeviceLocked() != null - && mLogicalDisplay.getPrimaryDisplayDeviceLocked() - .getDisplayDeviceInfoLocked().type == Display.TYPE_INTERNAL; - final String thermalBrightnessThrottlingDataId = - mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId; - final String powerThrottlingDataId = - mLogicalDisplay.getPowerThrottlingDataIdLocked(); - - mHandler.postAtTime(() -> { - boolean changed = false; - if (mDisplayDevice != device) { - changed = true; - mDisplayDevice = device; - mUniqueDisplayId = uniqueId; - mDisplayStatsId = mUniqueDisplayId.hashCode(); - mDisplayDeviceConfig = config; - mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; - loadFromDisplayDeviceConfig(token, info, hbmMetadata); - mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config); - - // Since the underlying display-device changed, we really don't know the - // last command that was sent to change it's state. Let's assume it is unknown so - // that we trigger a change immediately. - mPowerState.resetScreenState(); - } else if (!Objects.equals(mThermalBrightnessThrottlingDataId, - thermalBrightnessThrottlingDataId)) { - changed = true; - mThermalBrightnessThrottlingDataId = thermalBrightnessThrottlingDataId; - mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( - config.getThermalBrightnessThrottlingDataMapByThrottlingId(), - mThermalBrightnessThrottlingDataId, - mUniqueDisplayId); - } - if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) { - changed = true; - mIsEnabled = isEnabled; - mIsInTransition = isInTransition; - } - - mIsDisplayInternal = isDisplayInternal; - // using local variables here, when mBrightnessThrottler is removed, - // mThermalBrightnessThrottlingDataId could be removed as well - // changed = true will be not needed - clampers are maintaining their state and - // will call updatePowerState if needed. - mBrightnessClamperController.onDisplayChanged( - new BrightnessClamperController.DisplayDeviceData(uniqueId, - thermalBrightnessThrottlingDataId, powerThrottlingDataId, config)); - - if (changed) { - updatePowerState(); - } - }, mClock.uptimeMillis()); - } - - /** - * Unregisters all listeners and interrupts all running threads; halting future work. - * - * This method should be called when the DisplayPowerController2 is no longer in use; i.e. when - * the {@link #mDisplayId display} has been removed. - */ - @Override - public void stop() { - synchronized (mLock) { - clearDisplayBrightnessFollowersLocked(); - - mStopped = true; - Message msg = mHandler.obtainMessage(MSG_STOP); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.stop(); - } - - mDisplayBrightnessController.stop(); - - mContext.getContentResolver().unregisterContentObserver(mSettingsObserver); - } - } - - private void loadFromDisplayDeviceConfig(IBinder token, DisplayDeviceInfo info, - HighBrightnessModeMetadata hbmMetadata) { - // All properties that depend on the associated DisplayDevice and the DDC must be - // updated here. - loadBrightnessRampRates(); - loadNitsRange(mContext.getResources()); - setUpAutoBrightness(mContext, mHandler); - reloadReduceBrightColours(); - setAnimatorRampSpeeds(/* isIdleMode= */ false); - - mBrightnessRangeController.loadFromConfig(hbmMetadata, token, info, mDisplayDeviceConfig); - mBrightnessThrottler.loadThermalBrightnessThrottlingDataFromDisplayDeviceConfig( - mDisplayDeviceConfig.getThermalBrightnessThrottlingDataMapByThrottlingId(), - mThermalBrightnessThrottlingDataId, mUniqueDisplayId); - } - - private void sendUpdatePowerState() { - synchronized (mLock) { - sendUpdatePowerStateLocked(); - } - } - - @GuardedBy("mLock") - private void sendUpdatePowerStateLocked() { - if (!mStopped && !mPendingUpdatePowerStateLocked) { - mPendingUpdatePowerStateLocked = true; - Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - } - - private void initialize(int displayState) { - mPowerState = mInjector.getDisplayPowerState(mBlanker, - mColorFadeEnabled ? new ColorFade(mDisplayId) : null, mDisplayId, displayState); - - if (mColorFadeEnabled) { - mColorFadeOnAnimator = ObjectAnimator.ofFloat( - mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f); - mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS); - mColorFadeOnAnimator.addListener(mAnimatorListener); - - mColorFadeOffAnimator = ObjectAnimator.ofFloat( - mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f); - mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS); - mColorFadeOffAnimator.addListener(mAnimatorListener); - } - - mScreenBrightnessRampAnimator = mInjector.getDualRampAnimator(mPowerState, - DisplayPowerState.SCREEN_BRIGHTNESS_FLOAT, - DisplayPowerState.SCREEN_SDR_BRIGHTNESS_FLOAT); - setAnimatorRampSpeeds(mAutomaticBrightnessController != null - && mAutomaticBrightnessController.isInIdleMode()); - mScreenBrightnessRampAnimator.setListener(mRampAnimatorListener); - - noteScreenState(mPowerState.getScreenState()); - noteScreenBrightness(mPowerState.getScreenBrightness()); - - // Initialize all of the brightness tracking state - final float brightness = mDisplayBrightnessController.convertToAdjustedNits( - mPowerState.getScreenBrightness()); - if (mBrightnessTracker != null && brightness >= PowerManager.BRIGHTNESS_MIN) { - mBrightnessTracker.start(brightness); - } - - BrightnessSetting.BrightnessSettingListener brightnessSettingListener = brightnessValue -> { - Message msg = mHandler.obtainMessage(MSG_UPDATE_BRIGHTNESS, brightnessValue); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - }; - mDisplayBrightnessController - .registerBrightnessSettingChangeListener(brightnessSettingListener); - - mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ), - false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); - mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), - false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL); - if (mFlags.areAutoBrightnessModesEnabled()) { - mContext.getContentResolver().registerContentObserver( - Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_ALS), - /* notifyForDescendants= */ false, mSettingsObserver, UserHandle.USER_CURRENT); - } - handleBrightnessModeChange(); - } - - private void setUpAutoBrightness(Context context, Handler handler) { - mUseSoftwareAutoBrightnessConfig = mDisplayDeviceConfig.isAutoBrightnessAvailable(); - - if (!mUseSoftwareAutoBrightnessConfig) { - return; - } - - SparseArray<BrightnessMappingStrategy> brightnessMappers = new SparseArray<>(); - - BrightnessMappingStrategy defaultModeBrightnessMapper = - mInjector.getDefaultModeBrightnessMapper(context, mDisplayDeviceConfig, - mDisplayWhiteBalanceController); - brightnessMappers.append(AUTO_BRIGHTNESS_MODE_DEFAULT, - defaultModeBrightnessMapper); - - final boolean isIdleScreenBrightnessEnabled = context.getResources().getBoolean( - R.bool.config_enableIdleScreenBrightnessMode); - if (isIdleScreenBrightnessEnabled) { - BrightnessMappingStrategy idleModeBrightnessMapper = - BrightnessMappingStrategy.create(context, mDisplayDeviceConfig, - AUTO_BRIGHTNESS_MODE_IDLE, - mDisplayWhiteBalanceController); - if (idleModeBrightnessMapper != null) { - brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE, - idleModeBrightnessMapper); - } - } - - BrightnessMappingStrategy dozeModeBrightnessMapper = - BrightnessMappingStrategy.create(context, mDisplayDeviceConfig, - AUTO_BRIGHTNESS_MODE_DOZE, mDisplayWhiteBalanceController); - if (mFlags.areAutoBrightnessModesEnabled() && dozeModeBrightnessMapper != null) { - brightnessMappers.put(AUTO_BRIGHTNESS_MODE_DOZE, dozeModeBrightnessMapper); - } - - float userLux = BrightnessMappingStrategy.INVALID_LUX; - float userNits = BrightnessMappingStrategy.INVALID_NITS; - if (mAutomaticBrightnessController != null) { - userLux = mAutomaticBrightnessController.getUserLux(); - userNits = mAutomaticBrightnessController.getUserNits(); - } - - if (defaultModeBrightnessMapper != null) { - final float dozeScaleFactor = context.getResources().getFraction( - R.fraction.config_screenAutoBrightnessDozeScaleFactor, - 1, 1); - - // Ambient Lux - Active Mode Brightness Thresholds - float[] ambientBrighteningThresholds = - mDisplayDeviceConfig.getAmbientBrighteningPercentages(); - float[] ambientDarkeningThresholds = - mDisplayDeviceConfig.getAmbientDarkeningPercentages(); - float[] ambientBrighteningLevels = - mDisplayDeviceConfig.getAmbientBrighteningLevels(); - float[] ambientDarkeningLevels = - mDisplayDeviceConfig.getAmbientDarkeningLevels(); - float ambientDarkeningMinThreshold = - mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(); - float ambientBrighteningMinThreshold = - mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(); - HysteresisLevels ambientBrightnessThresholds = mInjector.getHysteresisLevels( - ambientBrighteningThresholds, ambientDarkeningThresholds, - ambientBrighteningLevels, ambientDarkeningLevels, ambientDarkeningMinThreshold, - ambientBrighteningMinThreshold); - - // Display - Active Mode Brightness Thresholds - float[] screenBrighteningThresholds = - mDisplayDeviceConfig.getScreenBrighteningPercentages(); - float[] screenDarkeningThresholds = - mDisplayDeviceConfig.getScreenDarkeningPercentages(); - float[] screenBrighteningLevels = - mDisplayDeviceConfig.getScreenBrighteningLevels(); - float[] screenDarkeningLevels = - mDisplayDeviceConfig.getScreenDarkeningLevels(); - float screenDarkeningMinThreshold = - mDisplayDeviceConfig.getScreenDarkeningMinThreshold(); - float screenBrighteningMinThreshold = - mDisplayDeviceConfig.getScreenBrighteningMinThreshold(); - HysteresisLevels screenBrightnessThresholds = mInjector.getHysteresisLevels( - screenBrighteningThresholds, screenDarkeningThresholds, - screenBrighteningLevels, screenDarkeningLevels, screenDarkeningMinThreshold, - screenBrighteningMinThreshold, true); - - // Ambient Lux - Idle Screen Brightness Thresholds - float ambientDarkeningMinThresholdIdle = - mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle(); - float ambientBrighteningMinThresholdIdle = - mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle(); - float[] ambientBrighteningThresholdsIdle = - mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle(); - float[] ambientDarkeningThresholdsIdle = - mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(); - float[] ambientBrighteningLevelsIdle = - mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle(); - float[] ambientDarkeningLevelsIdle = - mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(); - HysteresisLevels ambientBrightnessThresholdsIdle = mInjector.getHysteresisLevels( - ambientBrighteningThresholdsIdle, ambientDarkeningThresholdsIdle, - ambientBrighteningLevelsIdle, ambientDarkeningLevelsIdle, - ambientDarkeningMinThresholdIdle, ambientBrighteningMinThresholdIdle); - - // Display - Idle Screen Brightness Thresholds - float screenDarkeningMinThresholdIdle = - mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle(); - float screenBrighteningMinThresholdIdle = - mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle(); - float[] screenBrighteningThresholdsIdle = - mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle(); - float[] screenDarkeningThresholdsIdle = - mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle(); - float[] screenBrighteningLevelsIdle = - mDisplayDeviceConfig.getScreenBrighteningLevelsIdle(); - float[] screenDarkeningLevelsIdle = - mDisplayDeviceConfig.getScreenDarkeningLevelsIdle(); - HysteresisLevels screenBrightnessThresholdsIdle = mInjector.getHysteresisLevels( - screenBrighteningThresholdsIdle, screenDarkeningThresholdsIdle, - screenBrighteningLevelsIdle, screenDarkeningLevelsIdle, - screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle); - - long brighteningLightDebounce = mDisplayDeviceConfig - .getAutoBrightnessBrighteningLightDebounce(); - long darkeningLightDebounce = mDisplayDeviceConfig - .getAutoBrightnessDarkeningLightDebounce(); - long brighteningLightDebounceIdle = mDisplayDeviceConfig - .getAutoBrightnessBrighteningLightDebounceIdle(); - long darkeningLightDebounceIdle = mDisplayDeviceConfig - .getAutoBrightnessDarkeningLightDebounceIdle(); - boolean autoBrightnessResetAmbientLuxAfterWarmUp = context.getResources().getBoolean( - R.bool.config_autoBrightnessResetAmbientLuxAfterWarmUp); - - int lightSensorWarmUpTimeConfig = context.getResources().getInteger( - R.integer.config_lightSensorWarmupTime); - int lightSensorRate = context.getResources().getInteger( - R.integer.config_autoBrightnessLightSensorRate); - int initialLightSensorRate = context.getResources().getInteger( - R.integer.config_autoBrightnessInitialLightSensorRate); - if (initialLightSensorRate == -1) { - initialLightSensorRate = lightSensorRate; - } else if (initialLightSensorRate > lightSensorRate) { - Slog.w(mTag, "Expected config_autoBrightnessInitialLightSensorRate (" - + initialLightSensorRate + ") to be less than or equal to " - + "config_autoBrightnessLightSensorRate (" + lightSensorRate + ")."); - } - - loadAmbientLightSensor(); - // BrightnessTracker should only use one light sensor, we want to use the light sensor - // from the default display and not e.g. temporary displays when switching layouts. - if (mBrightnessTracker != null && mDisplayId == Display.DEFAULT_DISPLAY) { - mBrightnessTracker.setLightSensor(mLightSensor); - } - - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.stop(); - } - mAutomaticBrightnessController = mInjector.getAutomaticBrightnessController( - this, handler.getLooper(), mSensorManager, mLightSensor, - brightnessMappers, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate, - initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce, - brighteningLightDebounceIdle, darkeningLightDebounceIdle, - autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds, - screenBrightnessThresholds, ambientBrightnessThresholdsIdle, - screenBrightnessThresholdsIdle, mContext, mBrightnessRangeController, - mBrightnessThrottler, mDisplayDeviceConfig.getAmbientHorizonShort(), - mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userNits); - mDisplayBrightnessController.setAutomaticBrightnessController( - mAutomaticBrightnessController); - - mAutomaticBrightnessStrategy - .setAutomaticBrightnessController(mAutomaticBrightnessController); - mBrightnessEventRingBuffer = - new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX); - - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.stop(); - mScreenOffBrightnessSensorController = null; - } - loadScreenOffBrightnessSensor(); - int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux(); - if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) { - mScreenOffBrightnessSensorController = - mInjector.getScreenOffBrightnessSensorController( - mSensorManager, - mScreenOffBrightnessSensor, - mHandler, - SystemClock::uptimeMillis, - sensorValueToLux, - defaultModeBrightnessMapper); - } - } else { - mUseSoftwareAutoBrightnessConfig = false; - } - } - - private void loadBrightnessRampRates() { - mBrightnessRampRateFastDecrease = mDisplayDeviceConfig.getBrightnessRampFastDecrease(); - mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease(); - mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease(); - mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease(); - mBrightnessRampRateSlowDecreaseIdle = - mDisplayDeviceConfig.getBrightnessRampSlowDecreaseIdle(); - mBrightnessRampRateSlowIncreaseIdle = - mDisplayDeviceConfig.getBrightnessRampSlowIncreaseIdle(); - mBrightnessRampDecreaseMaxTimeMillis = - mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(); - mBrightnessRampIncreaseMaxTimeMillis = - mDisplayDeviceConfig.getBrightnessRampIncreaseMaxMillis(); - mBrightnessRampDecreaseMaxTimeIdleMillis = - mDisplayDeviceConfig.getBrightnessRampDecreaseMaxIdleMillis(); - mBrightnessRampIncreaseMaxTimeIdleMillis = - mDisplayDeviceConfig.getBrightnessRampIncreaseMaxIdleMillis(); - } - - private void loadNitsRange(Resources resources) { - if (mDisplayDeviceConfig != null && mDisplayDeviceConfig.getNits() != null) { - mNitsRange = mDisplayDeviceConfig.getNits(); - } else { - Slog.w(mTag, "Screen brightness nits configuration is unavailable; falling back"); - mNitsRange = BrightnessMappingStrategy.getFloatArray(resources - .obtainTypedArray(R.array.config_screenBrightnessNits)); - } - } - - private void reloadReduceBrightColours() { - if (mCdsi != null && mCdsi.isReduceBrightColorsActivated()) { - applyReduceBrightColorsSplineAdjustment(); - } - } - - @Override - public void setAutomaticScreenBrightnessMode( - @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - boolean isIdle = mode == AUTO_BRIGHTNESS_MODE_IDLE; - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.switchMode(mode); - setAnimatorRampSpeeds(isIdle); - } - Message msg = mHandler.obtainMessage(); - msg.what = MSG_SET_DWBC_STRONG_MODE; - msg.arg1 = isIdle ? 1 : 0; - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - - private void setAnimatorRampSpeeds(boolean isIdle) { - if (mScreenBrightnessRampAnimator == null) { - return; - } - if (mFlags.isAdaptiveTone1Enabled() && isIdle) { - mScreenBrightnessRampAnimator.setAnimationTimeLimits( - mBrightnessRampIncreaseMaxTimeIdleMillis, - mBrightnessRampDecreaseMaxTimeIdleMillis); - } else { - mScreenBrightnessRampAnimator.setAnimationTimeLimits( - mBrightnessRampIncreaseMaxTimeMillis, - mBrightnessRampDecreaseMaxTimeMillis); - } - } - - private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - sendUpdatePowerState(); - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationCancel(Animator animation) { - } - }; - - private final RampAnimator.Listener mRampAnimatorListener = new RampAnimator.Listener() { - @Override - public void onAnimationEnd() { - sendUpdatePowerState(); - Message msg = mHandler.obtainMessage(MSG_BRIGHTNESS_RAMP_DONE); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - }; - - /** Clean up all resources that are accessed via the {@link #mHandler} thread. */ - private void cleanupHandlerThreadAfterStop() { - mDisplayPowerProximityStateController.cleanup(); - mBrightnessRangeController.stop(); - mBrightnessThrottler.stop(); - mBrightnessClamperController.stop(); - mHandler.removeCallbacksAndMessages(null); - - // Release any outstanding wakelocks we're still holding because of pending messages. - mWakelockController.releaseAll(); - - final float brightness = mPowerState != null - ? mPowerState.getScreenBrightness() - : PowerManager.BRIGHTNESS_MIN; - reportStats(brightness); - - if (mPowerState != null) { - mPowerState.stop(); - mPowerState = null; - } - - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.stop(); - } - - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setEnabled(false); - } - } - - // Call from handler thread - private void updatePowerState() { - Trace.traceBegin(Trace.TRACE_TAG_POWER, - "DisplayPowerController#updatePowerState"); - updatePowerStateInternal(); - Trace.traceEnd(Trace.TRACE_TAG_POWER); - } - - private void updatePowerStateInternal() { - // Update the power state request. - final boolean mustNotify; - final int previousPolicy; - boolean mustInitialize = false; - mBrightnessReasonTemp.set(null); - mTempBrightnessEvent.reset(); - SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers; - synchronized (mLock) { - if (mStopped) { - return; - } - mPendingUpdatePowerStateLocked = false; - if (mPendingRequestLocked == null) { - return; // wait until first actual power request - } - - if (mPowerRequest == null) { - mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked); - mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); - mPendingRequestChangedLocked = false; - mustInitialize = true; - // Assume we're on and bright until told otherwise, since that's the state we turn - // on in. - previousPolicy = DisplayPowerRequest.POLICY_BRIGHT; - } else if (mPendingRequestChangedLocked) { - previousPolicy = mPowerRequest.policy; - mPowerRequest.copyFrom(mPendingRequestLocked); - mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked(); - mPendingRequestChangedLocked = false; - mDisplayReadyLocked = false; - } else { - previousPolicy = mPowerRequest.policy; - } - - mustNotify = !mDisplayReadyLocked; - - displayBrightnessFollowers = mDisplayBrightnessFollowers.clone(); - } - - int state = mDisplayStateController - .updateDisplayState(mPowerRequest, mIsEnabled, mIsInTransition); - - // Initialize things the first time the power state is changed. - if (mustInitialize) { - initialize(readyToUpdateDisplayState() ? state : Display.STATE_UNKNOWN); - } - - // Animate the screen state change unless already animating. - // The transition may be deferred, so after this point we will use the - // actual state instead of the desired one. - animateScreenStateChange(state, mDisplayStateController.shouldPerformScreenOffTransition()); - state = mPowerState.getScreenState(); - - // Switch to doze auto-brightness mode if needed - if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null - && !mAutomaticBrightnessController.isInIdleMode()) { - setAutomaticScreenBrightnessMode(Display.isDozeState(state) - ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); - } - - final boolean userSetBrightnessChanged = mDisplayBrightnessController - .updateUserSetScreenBrightness(); - - DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController - .updateBrightness(mPowerRequest, state); - float brightnessState = displayBrightnessState.getBrightness(); - float rawBrightnessState = displayBrightnessState.getBrightness(); - mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason()); - boolean slowChange = displayBrightnessState.isSlowChange(); - // custom transition duration - float customAnimationRate = displayBrightnessState.getCustomAnimationRate(); - - // Set up the ScreenOff controller used when coming out of SCREEN_OFF and the ALS sensor - // doesn't yet have a valid lux value to use with auto-brightness. - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController - .setLightSensorEnabled(displayBrightnessState.getShouldUseAutoBrightness() - && mIsEnabled && (state == Display.STATE_OFF - || (state == Display.STATE_DOZE - && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())) - && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); - } - - // Take note if the short term model was already active before applying the current - // request changes. - final boolean wasShortTermModelActive = - mAutomaticBrightnessStrategy.isShortTermModelActive(); - mAutomaticBrightnessStrategy.setAutoBrightnessState(state, - mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(), - mBrightnessReasonTemp.getReason(), mPowerRequest.policy, - mDisplayBrightnessController.getLastUserSetScreenBrightness(), - userSetBrightnessChanged); - - // If the brightness is already set then it's been overridden by something other than the - // user, or is a temporary adjustment. - boolean userInitiatedChange = (Float.isNaN(brightnessState)) - && (mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged() - || userSetBrightnessChanged); - - mBrightnessRangeController.setAutoBrightnessEnabled( - mAutomaticBrightnessStrategy.isAutoBrightnessEnabled() - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED - : mAutomaticBrightnessStrategy.isAutoBrightnessDisabledDueToDisplayOff() - ? AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE - : AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); - - boolean updateScreenBrightnessSetting = - displayBrightnessState.shouldUpdateScreenBrightnessSetting(); - float currentBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness(); - // Apply auto-brightness. - int brightnessAdjustmentFlags = 0; - if (Float.isNaN(brightnessState)) { - if (mAutomaticBrightnessStrategy.isAutoBrightnessEnabled()) { - brightnessState = mAutomaticBrightnessStrategy.getAutomaticScreenBrightness( - mTempBrightnessEvent); - if (BrightnessUtils.isValidBrightnessValue(brightnessState) - || brightnessState == PowerManager.BRIGHTNESS_OFF_FLOAT) { - rawBrightnessState = mAutomaticBrightnessController - .getRawAutomaticScreenBrightness(); - brightnessState = clampScreenBrightness(brightnessState); - // slowly adapt to auto-brightness - // TODO(b/253226419): slowChange should be decided by strategy.updateBrightness - slowChange = mAutomaticBrightnessStrategy.hasAppliedAutoBrightness() - && !mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentChanged(); - brightnessAdjustmentFlags = - mAutomaticBrightnessStrategy.getAutoBrightnessAdjustmentReasonsFlags(); - updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; - mAutomaticBrightnessStrategy.setAutoBrightnessApplied(true); - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC); - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.setLightSensorEnabled(false); - } - } else { - mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false); - } - } - } else { - // Any non-auto-brightness values such as override or temporary should still be subject - // to clamping so that they don't go beyond the current max as specified by HBM - // Controller. - brightnessState = clampScreenBrightness(brightnessState); - mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false); - } - - // Use default brightness when dozing unless overridden. - if ((Float.isNaN(brightnessState)) - && Display.isDozeState(state)) { - rawBrightnessState = mScreenBrightnessDozeConfig; - brightnessState = clampScreenBrightness(rawBrightnessState); - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT); - } - - // The ALS is not available yet - use the screen off sensor to determine the initial - // brightness - if (Float.isNaN(brightnessState) && mAutomaticBrightnessStrategy.isAutoBrightnessEnabled() - && mScreenOffBrightnessSensorController != null) { - rawBrightnessState = - mScreenOffBrightnessSensorController.getAutomaticScreenBrightness(); - brightnessState = rawBrightnessState; - if (BrightnessUtils.isValidBrightnessValue(brightnessState)) { - brightnessState = clampScreenBrightness(brightnessState); - updateScreenBrightnessSetting = mDisplayBrightnessController.getCurrentBrightness() - != brightnessState; - mBrightnessReasonTemp.setReason( - BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR); - } - } - - // Apply manual brightness. - if (Float.isNaN(brightnessState)) { - rawBrightnessState = currentBrightnessSetting; - brightnessState = clampScreenBrightness(rawBrightnessState); - if (brightnessState != currentBrightnessSetting) { - // The manually chosen screen brightness is outside of the currently allowed - // range (i.e., high-brightness-mode), make sure we tell the rest of the system - // by updating the setting. - updateScreenBrightnessSetting = true; - } - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_MANUAL); - } - - float ambientLux = mAutomaticBrightnessController == null ? 0 - : mAutomaticBrightnessController.getAmbientLux(); - for (int i = 0; i < displayBrightnessFollowers.size(); i++) { - DisplayPowerControllerInterface follower = displayBrightnessFollowers.valueAt(i); - follower.setBrightnessToFollow(rawBrightnessState, - mDisplayBrightnessController.convertToNits(rawBrightnessState), - ambientLux, slowChange); - } - - // Now that a desired brightness has been calculated, apply brightness throttling. The - // dimming and low power transformations that follow can only dim brightness further. - // - // We didn't do this earlier through brightness clamping because we need to know both - // unthrottled (unclamped/ideal) and throttled brightness levels for subsequent operations. - // Note throttling effectively changes the allowed brightness range, so, similarly to HBM, - // we broadcast this change through setting. - final float unthrottledBrightnessState = brightnessState; - DisplayBrightnessState clampedState = mBrightnessClamperController.clamp(mPowerRequest, - brightnessState, slowChange); - - brightnessState = clampedState.getBrightness(); - slowChange = clampedState.isSlowChange(); - // faster rate wins, at this point customAnimationRate == -1, strategy does not control - // customAnimationRate. Should be revisited if strategy start setting this value - customAnimationRate = Math.max(customAnimationRate, clampedState.getCustomAnimationRate()); - mBrightnessReasonTemp.addModifier(clampedState.getBrightnessReason().getModifier()); - - if (updateScreenBrightnessSetting) { - // Tell the rest of the system about the new brightness in case we had to change it - // for things like auto-brightness or high-brightness-mode. Note that we do this - // only considering maxBrightness (ignoring brightness modifiers like low power or dim) - // so that the slider accurately represents the full possible range, - // even if they range changes what it means in absolute terms. - mDisplayBrightnessController.updateScreenBrightnessSetting( - MathUtils.constrain(unthrottledBrightnessState, - clampedState.getMinBrightness(), clampedState.getMaxBrightness())); - } - - // The current brightness to use has been calculated at this point, and HbmController should - // be notified so that it can accurately calculate HDR or HBM levels. We specifically do it - // here instead of having HbmController listen to the brightness setting because certain - // brightness sources (such as an app override) are not saved to the setting, but should be - // reflected in HBM calculations. - mBrightnessRangeController.onBrightnessChanged(brightnessState, unthrottledBrightnessState, - mBrightnessClamperController.getBrightnessMaxReason()); - - // Animate the screen brightness when the screen is on or dozing. - // Skip the animation when the screen is off or suspended. - boolean brightnessAdjusted = false; - final boolean brightnessIsTemporary = - (mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_TEMPORARY) - || mAutomaticBrightnessStrategy - .isTemporaryAutoBrightnessAdjustmentApplied(); - if (!mPendingScreenOff) { - if (mSkipScreenOnBrightnessRamp) { - if (state == Display.STATE_ON) { - if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) { - mInitialAutoBrightness = brightnessState; - mSkipRampState = RAMP_STATE_SKIP_INITIAL; - } else if (mSkipRampState == RAMP_STATE_SKIP_INITIAL - && mUseSoftwareAutoBrightnessConfig - && !BrightnessSynchronizer.floatEquals(brightnessState, - mInitialAutoBrightness)) { - mSkipRampState = RAMP_STATE_SKIP_AUTOBRIGHT; - } else if (mSkipRampState == RAMP_STATE_SKIP_AUTOBRIGHT) { - mSkipRampState = RAMP_STATE_SKIP_NONE; - } - } else { - mSkipRampState = RAMP_STATE_SKIP_NONE; - } - } - - final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState - != RAMP_STATE_SKIP_NONE) || mDisplayPowerProximityStateController - .shouldSkipRampBecauseOfProximityChangeToNegative(); - // While dozing, sometimes the brightness is split into buckets. Rather than animating - // through the buckets, which is unlikely to be smooth in the first place, just jump - // right to the suggested brightness. - final boolean hasBrightnessBuckets = - Display.isDozeState(state) && mBrightnessBucketsInDozeConfig; - // If the color fade is totally covering the screen then we can change the backlight - // level without it being a noticeable jump since any actual content isn't yet visible. - final boolean isDisplayContentVisible = - mColorFadeEnabled && mPowerState.getColorFadeLevel() == 1.0f; - // We only want to animate the brightness if it is between 0.0f and 1.0f. - // brightnessState can contain the values -1.0f and NaN, which we do not want to - // animate to. To avoid this, we check the value first. - // If the brightnessState is off (-1.0f) we still want to animate to the minimum - // brightness (0.0f) to accommodate for LED displays, which can appear bright to the - // user even when the display is all black. We also clamp here in case some - // transformations to the brightness have pushed it outside of the currently - // allowed range. - float animateValue = clampScreenBrightness(brightnessState); - - // If there are any HDR layers on the screen, we have a special brightness value that we - // use instead. We still preserve the calculated brightness for Standard Dynamic Range - // (SDR) layers, but the main brightness value will be the one for HDR. - float sdrAnimateValue = animateValue; - // TODO(b/216365040): The decision to prevent HBM for HDR in low power mode should be - // done in HighBrightnessModeController. - if (mBrightnessRangeController.getHighBrightnessMode() - == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR - && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_DIMMED) == 0 - && (mBrightnessReasonTemp.getModifier() & BrightnessReason.MODIFIER_LOW_POWER) - == 0) { - // We want to scale HDR brightness level with the SDR level, we also need to restore - // SDR brightness immediately when entering dim or low power mode. - animateValue = mBrightnessRangeController.getHdrBrightnessValue(); - customAnimationRate = Math.max(customAnimationRate, - mBrightnessRangeController.getHdrTransitionRate()); - mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_HDR); - } - - // if doze or suspend state is requested, we want to finish brightnes animation fast - // to allow state animation to start - if (mPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE - && (mPowerRequest.dozeScreenState == Display.STATE_UNKNOWN // dozing - || mPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND - || mPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND)) { - customAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; - slowChange = false; - } - - final float currentBrightness = mPowerState.getScreenBrightness(); - final float currentSdrBrightness = mPowerState.getSdrScreenBrightness(); - - if (BrightnessUtils.isValidBrightnessValue(animateValue) - && (animateValue != currentBrightness - || sdrAnimateValue != currentSdrBrightness)) { - boolean skipAnimation = initialRampSkip || hasBrightnessBuckets - || !isDisplayContentVisible || brightnessIsTemporary; - final boolean isHdrOnlyChange = BrightnessSynchronizer.floatEquals( - sdrAnimateValue, currentSdrBrightness); - if (mFlags.isFastHdrTransitionsEnabled() && !skipAnimation && isHdrOnlyChange) { - // SDR brightness is unchanged, so animate quickly as this is only impacting - // a likely minority amount of display content - // ie, the highlights of an HDR video or UltraHDR image - slowChange = false; - - // Going from HDR to no HDR; visually this should be a "no-op" anyway - // as the remaining SDR content's brightness should be holding steady - // due to the sdr brightness not shifting - if (BrightnessSynchronizer.floatEquals(sdrAnimateValue, animateValue)) { - skipAnimation = true; - } - - // Going from no HDR to HDR; visually this is a significant scene change - // and the animation just prevents advanced clients from doing their own - // handling of enter/exit animations if they would like to do such a thing - if (BrightnessSynchronizer.floatEquals(sdrAnimateValue, currentBrightness)) { - skipAnimation = true; - } - } - if (skipAnimation) { - animateScreenBrightness(animateValue, sdrAnimateValue, - SCREEN_ANIMATION_RATE_MINIMUM); - } else if (customAnimationRate > 0) { - animateScreenBrightness(animateValue, sdrAnimateValue, - customAnimationRate, /* ignoreAnimationLimits = */true); - } else { - boolean isIncreasing = animateValue > currentBrightness; - final float rampSpeed; - final boolean idle = mAutomaticBrightnessController != null - && mAutomaticBrightnessController.isInIdleMode(); - if (isIncreasing && slowChange) { - rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle - : mBrightnessRampRateSlowIncrease; - } else if (isIncreasing && !slowChange) { - rampSpeed = mBrightnessRampRateFastIncrease; - } else if (!isIncreasing && slowChange) { - rampSpeed = idle ? mBrightnessRampRateSlowDecreaseIdle - : mBrightnessRampRateSlowDecrease; - } else { - rampSpeed = mBrightnessRampRateFastDecrease; - } - animateScreenBrightness(animateValue, sdrAnimateValue, rampSpeed); - } - } - - notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange, - wasShortTermModelActive, mAutomaticBrightnessStrategy.isAutoBrightnessEnabled(), - brightnessIsTemporary, displayBrightnessState.getShouldUseAutoBrightness()); - - // We save the brightness info *after* the brightness setting has been changed and - // adjustments made so that the brightness info reflects the latest value. - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), - animateValue, clampedState); - } else { - brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), clampedState); - } - - // Only notify if the brightness adjustment is not temporary (i.e. slider has been released) - if (brightnessAdjusted && !brightnessIsTemporary) { - postBrightnessChangeRunnable(); - } - - // Log any changes to what is currently driving the brightness setting. - if (!mBrightnessReasonTemp.equals(mBrightnessReason) || brightnessAdjustmentFlags != 0) { - Slog.v(mTag, "Brightness [" + brightnessState + "] reason changing to: '" - + mBrightnessReasonTemp.toString(brightnessAdjustmentFlags) - + "', previous reason: '" + mBrightnessReason + "'."); - mBrightnessReason.set(mBrightnessReasonTemp); - } else if (mBrightnessReasonTemp.getReason() == BrightnessReason.REASON_MANUAL - && userSetBrightnessChanged) { - Slog.v(mTag, "Brightness [" + brightnessState + "] manual adjustment."); - } - - - // Log brightness events when a detail of significance has changed. Generally this is the - // brightness itself changing, but also includes data like HBM cap, thermal throttling - // brightness cap, RBC state, etc. - mTempBrightnessEvent.setTime(System.currentTimeMillis()); - mTempBrightnessEvent.setBrightness(brightnessState); - mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId); - mTempBrightnessEvent.setReason(mBrightnessReason); - mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax()); - mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode()); - mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags() - | (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0) - | (mPowerRequest.lowPowerMode ? BrightnessEvent.FLAG_LOW_POWER_MODE : 0)); - mTempBrightnessEvent.setRbcStrength(mCdsi != null - ? mCdsi.getReduceBrightColorsStrength() : -1); - mTempBrightnessEvent.setPowerFactor(mPowerRequest.screenLowPowerBrightnessFactor); - mTempBrightnessEvent.setWasShortTermModelActive(wasShortTermModelActive); - mTempBrightnessEvent.setDisplayBrightnessStrategyName(displayBrightnessState - .getDisplayBrightnessStrategyName()); - mTempBrightnessEvent.setAutomaticBrightnessEnabled( - displayBrightnessState.getShouldUseAutoBrightness()); - // Temporary is what we use during slider interactions. We avoid logging those so that - // we don't spam logcat when the slider is being used. - boolean tempToTempTransition = - mTempBrightnessEvent.getReason().getReason() == BrightnessReason.REASON_TEMPORARY - && mLastBrightnessEvent.getReason().getReason() - == BrightnessReason.REASON_TEMPORARY; - // Purely for dumpsys; - final boolean isRbcEvent = - mLastBrightnessEvent.isRbcEnabled() != mTempBrightnessEvent.isRbcEnabled(); - - if ((!mTempBrightnessEvent.equalsMainData(mLastBrightnessEvent) && !tempToTempTransition) - || brightnessAdjustmentFlags != 0) { - mTempBrightnessEvent.setInitialBrightness(mLastBrightnessEvent.getBrightness()); - mLastBrightnessEvent.copyFrom(mTempBrightnessEvent); - BrightnessEvent newEvent = new BrightnessEvent(mTempBrightnessEvent); - // Adjustment flags (and user-set flag) only get added after the equality checks since - // they are transient. - newEvent.setAdjustmentFlags(brightnessAdjustmentFlags); - newEvent.setFlags(newEvent.getFlags() | (userSetBrightnessChanged - ? BrightnessEvent.FLAG_USER_SET : 0)); - Slog.i(mTag, newEvent.toString(/* includeTime= */ false)); - - if (userSetBrightnessChanged - || newEvent.getReason().getReason() != BrightnessReason.REASON_TEMPORARY) { - logBrightnessEvent(newEvent, unthrottledBrightnessState); - } - if (mBrightnessEventRingBuffer != null) { - mBrightnessEventRingBuffer.append(newEvent); - } - if (isRbcEvent) { - mRbcEventRingBuffer.append(newEvent); - } - - } - - // Update display white-balance. - if (mDisplayWhiteBalanceController != null) { - if (state == Display.STATE_ON && mDisplayWhiteBalanceSettings.isEnabled()) { - mDisplayWhiteBalanceController.setEnabled(true); - mDisplayWhiteBalanceController.updateDisplayColorTemperature(); - } else { - mDisplayWhiteBalanceController.setEnabled(false); - } - } - - // Determine whether the display is ready for use in the newly requested state. - // Note that we do not wait for the brightness ramp animation to complete before - // reporting the display is ready because we only need to ensure the screen is in the - // right power state even as it continues to converge on the desired brightness. - final boolean ready = mPendingScreenOnUnblocker == null - && mPendingScreenOnUnblockerByDisplayOffload == null - && (!mColorFadeEnabled || (!mColorFadeOnAnimator.isStarted() - && !mColorFadeOffAnimator.isStarted())) - && mPowerState.waitUntilClean(mCleanListener); - final boolean finished = ready - && !mScreenBrightnessRampAnimator.isAnimating(); - - // Notify policy about screen turned on. - if (ready && state != Display.STATE_OFF - && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_ON) { - setReportedScreenState(REPORTED_TO_POLICY_SCREEN_ON); - mWindowManagerPolicy.screenTurnedOn(mDisplayId); - } - - // Grab a wake lock if we have unfinished business. - if (!finished) { - mWakelockController.acquireWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); - } - - // Notify the power manager when ready. - if (ready && mustNotify) { - // Send state change. - synchronized (mLock) { - if (!mPendingRequestChangedLocked) { - mDisplayReadyLocked = true; - - if (DEBUG) { - Slog.d(mTag, "Display ready!"); - } - } - } - sendOnStateChangedWithWakelock(); - } - - // Release the wake lock when we have no unfinished business. - if (finished) { - mWakelockController.releaseWakelock(WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); - } - - // Record if dozing for future comparison. - mDozing = state != Display.STATE_ON; - - if (previousPolicy != mPowerRequest.policy) { - logDisplayPolicyChanged(mPowerRequest.policy); - } - } - - private void setDwbcOverride(float cct) { - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.setAmbientColorTemperatureOverride(cct); - // The ambient color temperature override is only applied when the ambient color - // temperature changes or is updated, so it doesn't necessarily change the screen color - // temperature immediately. So, let's make it! - // We can call this directly, since we're already on the handler thread. - updatePowerState(); - } - } - - private void setDwbcStrongMode(int arg) { - if (mDisplayWhiteBalanceController != null) { - final boolean isIdle = (arg == 1); - mDisplayWhiteBalanceController.setStrongModeEnabled(isIdle); - } - } - - private void setDwbcLoggingEnabled(int arg) { - if (mDisplayWhiteBalanceController != null) { - final boolean enabled = (arg == 1); - mDisplayWhiteBalanceController.setLoggingEnabled(enabled); - mDisplayWhiteBalanceSettings.setLoggingEnabled(enabled); - } - } - - @Override - public void updateBrightness() { - sendUpdatePowerState(); - } - - /** - * Ignores the proximity sensor until the sensor state changes, but only if the sensor is - * currently enabled and forcing the screen to be dark. - */ - @Override - public void ignoreProximitySensorUntilChanged() { - mDisplayPowerProximityStateController.ignoreProximitySensorUntilChanged(); - } - - @Override - public void setBrightnessConfiguration(BrightnessConfiguration c, - boolean shouldResetShortTermModel) { - Message msg = mHandler.obtainMessage(MSG_CONFIGURE_BRIGHTNESS, - shouldResetShortTermModel ? 1 : 0, /* unused */ 0, c); - msg.sendToTarget(); - } - - @Override - public void setTemporaryBrightness(float brightness) { - Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS, - Float.floatToIntBits(brightness), 0 /*unused*/); - msg.sendToTarget(); - } - - @Override - public void setTemporaryAutoBrightnessAdjustment(float adjustment) { - Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT, - Float.floatToIntBits(adjustment), 0 /*unused*/); - msg.sendToTarget(); - } - - @Override - public void setBrightnessFromOffload(float brightness) { - Message msg = mHandler.obtainMessage(MSG_SET_BRIGHTNESS_FROM_OFFLOAD, - Float.floatToIntBits(brightness), 0 /*unused*/); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - - @Override - public float[] getAutoBrightnessLevels( - @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - int preset = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, - Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, UserHandle.USER_CURRENT); - return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevels(mode, preset); - } - - @Override - public float[] getAutoBrightnessLuxLevels( - @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { - int preset = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, - Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, UserHandle.USER_CURRENT); - return mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(mode, preset); - } - - @Override - public BrightnessInfo getBrightnessInfo() { - synchronized (mCachedBrightnessInfo) { - return new BrightnessInfo( - mCachedBrightnessInfo.brightness.value, - mCachedBrightnessInfo.adjustedBrightness.value, - mCachedBrightnessInfo.brightnessMin.value, - mCachedBrightnessInfo.brightnessMax.value, - mCachedBrightnessInfo.hbmMode.value, - mCachedBrightnessInfo.hbmTransitionPoint.value, - mCachedBrightnessInfo.brightnessMaxReason.value); - } - } - - @Override - public void onBootCompleted() { - Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - - private boolean saveBrightnessInfo(float brightness) { - return saveBrightnessInfo(brightness, /* state= */ null); - } - - private boolean saveBrightnessInfo(float brightness, @Nullable DisplayBrightnessState state) { - return saveBrightnessInfo(brightness, brightness, state); - } - - private boolean saveBrightnessInfo(float brightness, float adjustedBrightness, - @Nullable DisplayBrightnessState state) { - synchronized (mCachedBrightnessInfo) { - float stateMax = state != null ? state.getMaxBrightness() : PowerManager.BRIGHTNESS_MAX; - float stateMin = state != null ? state.getMinBrightness() : PowerManager.BRIGHTNESS_MAX; - final float minBrightness = Math.max(stateMin, Math.min( - mBrightnessRangeController.getCurrentBrightnessMin(), stateMax)); - final float maxBrightness = Math.min( - mBrightnessRangeController.getCurrentBrightnessMax(), stateMax); - boolean changed = false; - - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightness, - brightness); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.adjustedBrightness, - adjustedBrightness); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin, - minBrightness); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax, - maxBrightness); - changed |= - mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode, - mBrightnessRangeController.getHighBrightnessMode()); - changed |= - mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint, - mBrightnessRangeController.getTransitionPoint()); - changed |= - mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason, - mBrightnessClamperController.getBrightnessMaxReason()); - return changed; - } - } - - void postBrightnessChangeRunnable() { - if (!mHandler.hasCallbacks(mOnBrightnessChangeRunnable)) { - mHandler.post(mOnBrightnessChangeRunnable); - } - } - - private HighBrightnessModeController createHbmControllerLocked( - HighBrightnessModeMetadata hbmMetadata, Runnable modeChangeCallback) { - final DisplayDeviceConfig ddConfig = mDisplayDevice.getDisplayDeviceConfig(); - final IBinder displayToken = mDisplayDevice.getDisplayTokenLocked(); - final String displayUniqueId = mDisplayDevice.getUniqueId(); - final DisplayDeviceConfig.HighBrightnessModeData hbmData = - ddConfig != null ? ddConfig.getHighBrightnessModeData() : null; - final DisplayDeviceInfo info = mDisplayDevice.getDisplayDeviceInfoLocked(); - return mInjector.getHighBrightnessModeController(mHandler, info.width, info.height, - displayToken, displayUniqueId, PowerManager.BRIGHTNESS_MIN, - PowerManager.BRIGHTNESS_MAX, hbmData, (sdrBrightness, maxDesiredHdrSdrRatio) -> - mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness, - maxDesiredHdrSdrRatio), modeChangeCallback, hbmMetadata, mContext); - } - - private BrightnessThrottler createBrightnessThrottlerLocked() { - final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked(); - final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig(); - return new BrightnessThrottler(mHandler, - () -> { - sendUpdatePowerState(); - postBrightnessChangeRunnable(); - }, mUniqueDisplayId, - mLogicalDisplay.getDisplayInfoLocked().thermalBrightnessThrottlingDataId, - ddConfig.getThermalBrightnessThrottlingDataMapByThrottlingId()); - } - - private void blockScreenOn() { - if (mPendingScreenOnUnblocker == null) { - Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0); - mPendingScreenOnUnblocker = new ScreenOnUnblocker(); - mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime(); - Slog.i(mTag, "Blocking screen on until initial contents have been drawn."); - } - } - - private void unblockScreenOn() { - if (mPendingScreenOnUnblocker != null) { - mPendingScreenOnUnblocker = null; - long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime; - Slog.i(mTag, "Unblocked screen on after " + delay + " ms"); - Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0); - } - } - - private void blockScreenOff() { - if (mPendingScreenOffUnblocker == null) { - Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0); - mPendingScreenOffUnblocker = new ScreenOffUnblocker(); - mScreenOffBlockStartRealTime = SystemClock.elapsedRealtime(); - Slog.i(mTag, "Blocking screen off"); - } - } - - private void unblockScreenOff() { - if (mPendingScreenOffUnblocker != null) { - mPendingScreenOffUnblocker = null; - long delay = SystemClock.elapsedRealtime() - mScreenOffBlockStartRealTime; - Slog.i(mTag, "Unblocked screen off after " + delay + " ms"); - Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_OFF_BLOCKED_TRACE_NAME, 0); - } - } - - private void blockScreenOnByDisplayOffload(DisplayOffloadSession displayOffloadSession) { - if (mPendingScreenOnUnblockerByDisplayOffload != null || displayOffloadSession == null) { - return; - } - mScreenTurningOnWasBlockedByDisplayOffload = true; - - Trace.asyncTraceBegin( - Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); - mScreenOnBlockByDisplayOffloadStartRealTime = SystemClock.elapsedRealtime(); - - mPendingScreenOnUnblockerByDisplayOffload = - () -> onDisplayOffloadUnblockScreenOn(displayOffloadSession); - if (!displayOffloadSession.blockScreenOn(mPendingScreenOnUnblockerByDisplayOffload)) { - mPendingScreenOnUnblockerByDisplayOffload = null; - long delay = - SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; - Slog.w(mTag, "Tried blocking screen on for offloading but failed. So, end trace after " - + delay + " ms."); - Trace.asyncTraceEnd( - Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); - return; - } - Slog.i(mTag, "Blocking screen on for offloading."); - } - - private void onDisplayOffloadUnblockScreenOn(DisplayOffloadSession displayOffloadSession) { - Message msg = mHandler.obtainMessage(MSG_OFFLOADING_SCREEN_ON_UNBLOCKED, - displayOffloadSession); - mHandler.sendMessage(msg); - } - - private void unblockScreenOnByDisplayOffload() { - if (mPendingScreenOnUnblockerByDisplayOffload == null) { - return; - } - mPendingScreenOnUnblockerByDisplayOffload = null; - long delay = SystemClock.elapsedRealtime() - mScreenOnBlockByDisplayOffloadStartRealTime; - Slog.i(mTag, "Unblocked screen on for offloading after " + delay + " ms"); - Trace.asyncTraceEnd( - Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_BY_DISPLAYOFFLOAD_TRACE_NAME, 0); - } - - private boolean setScreenState(int state) { - return setScreenState(state, false /*reportOnly*/); - } - - private boolean setScreenState(int state, boolean reportOnly) { - final boolean isOff = (state == Display.STATE_OFF); - final boolean isOn = (state == Display.STATE_ON); - final boolean changed = mPowerState.getScreenState() != state; - - // If the screen is turning on, give displayoffload a chance to do something before the - // screen actually turns on. - // TODO(b/316941732): add tests for this displayoffload screen-on blocker. - if (isOn && changed && !mScreenTurningOnWasBlockedByDisplayOffload) { - blockScreenOnByDisplayOffload(mDisplayOffloadSession); - } else if (!isOn && mScreenTurningOnWasBlockedByDisplayOffload) { - // No longer turning screen on, so unblock previous screen on blocking immediately. - unblockScreenOnByDisplayOffload(); - mScreenTurningOnWasBlockedByDisplayOffload = false; - } - - if (changed || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { - // If we are trying to turn screen off, give policy a chance to do something before we - // actually turn the screen off. - if (isOff && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { - if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON - || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) { - setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF); - blockScreenOff(); - mWindowManagerPolicy.screenTurningOff(mDisplayId, mPendingScreenOffUnblocker); - unblockScreenOff(); - } else if (mPendingScreenOffUnblocker != null) { - // Abort doing the state change until screen off is unblocked. - return false; - } - } - - if (!reportOnly && changed && readyToUpdateDisplayState() - && mPendingScreenOffUnblocker == null - && mPendingScreenOnUnblockerByDisplayOffload == null) { - Trace.traceCounter(Trace.TRACE_TAG_POWER, "ScreenState", state); - - String propertyKey = "debug.tracing.screen_state"; - String propertyValue = String.valueOf(state); - try { - // TODO(b/153319140) remove when we can get this from the above trace invocation - SystemProperties.set(propertyKey, propertyValue); - } catch (RuntimeException e) { - Slog.e(mTag, "Failed to set a system property: key=" + propertyKey - + " value=" + propertyValue + " " + e.getMessage()); - } - - mPowerState.setScreenState(state); - // Tell battery stats about the transition. - noteScreenState(state); - } - } - - // Tell the window manager policy when the screen is turned off or on unless it's due - // to the proximity sensor. We temporarily block turning the screen on until the - // window manager is ready by leaving a black surface covering the screen. - // This surface is essentially the final state of the color fade animation and - // it is only removed once the window manager tells us that the activity has - // finished drawing underneath. - if (isOff && mReportedScreenStateToPolicy != REPORTED_TO_POLICY_SCREEN_OFF - && !mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) { - setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); - unblockScreenOn(); - mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition); - } else if (!isOff - && mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_TURNING_OFF) { - - // We told policy already that screen was turning off, but now we changed our minds. - // Complete the full state transition on -> turningOff -> off. - unblockScreenOff(); - mWindowManagerPolicy.screenTurnedOff(mDisplayId, mIsInTransition); - setReportedScreenState(REPORTED_TO_POLICY_SCREEN_OFF); - } - if (!isOff - && (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_OFF - || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED)) { - setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_ON); - if (mPowerState.getColorFadeLevel() == 0.0f) { - blockScreenOn(); - } else { - unblockScreenOn(); - } - mWindowManagerPolicy.screenTurningOn(mDisplayId, mPendingScreenOnUnblocker); - } - - // Return true if the screen isn't blocked. - return mPendingScreenOnUnblocker == null - && mPendingScreenOnUnblockerByDisplayOffload == null; - } - - private void setReportedScreenState(int state) { - Trace.traceCounter(Trace.TRACE_TAG_POWER, "ReportedScreenStateToPolicy", state); - mReportedScreenStateToPolicy = state; - if (state == REPORTED_TO_POLICY_SCREEN_ON) { - mScreenTurningOnWasBlockedByDisplayOffload = false; - } - } - - private void loadAmbientLightSensor() { - final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY - ? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK; - mLightSensor = SensorUtils.findSensor(mSensorManager, - mDisplayDeviceConfig.getAmbientLightSensor(), fallbackType); - } - - private void loadScreenOffBrightnessSensor() { - mScreenOffBrightnessSensor = SensorUtils.findSensor(mSensorManager, - mDisplayDeviceConfig.getScreenOffBrightnessSensor(), SensorUtils.NO_FALLBACK); - } - - private float clampScreenBrightness(float value) { - if (Float.isNaN(value)) { - value = PowerManager.BRIGHTNESS_MIN; - } - return MathUtils.constrain(value, mBrightnessRangeController.getCurrentBrightnessMin(), - mBrightnessRangeController.getCurrentBrightnessMax()); - } - - private void animateScreenBrightness(float target, float sdrTarget, float rate) { - animateScreenBrightness(target, sdrTarget, rate, /* ignoreAnimationLimits = */false); - } - - private void animateScreenBrightness(float target, float sdrTarget, float rate, - boolean ignoreAnimationLimits) { - if (DEBUG) { - Slog.d(mTag, "Animating brightness: target=" + target + ", sdrTarget=" + sdrTarget - + ", rate=" + rate); - } - if (mScreenBrightnessRampAnimator.animateTo(target, sdrTarget, rate, - ignoreAnimationLimits)) { - Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", (int) target); - - String propertyKey = "debug.tracing.screen_brightness"; - String propertyValue = String.valueOf(target); - try { - // TODO(b/153319140) remove when we can get this from the above trace invocation - SystemProperties.set(propertyKey, propertyValue); - } catch (RuntimeException e) { - Slog.e(mTag, "Failed to set a system property: key=" + propertyKey - + " value=" + propertyValue + " " + e.getMessage()); - } - - noteScreenBrightness(target); - } - } - - private void animateScreenStateChange(int target, boolean performScreenOffTransition) { - // If there is already an animation in progress, don't interfere with it. - if (mColorFadeEnabled - && (mColorFadeOnAnimator.isStarted() || mColorFadeOffAnimator.isStarted())) { - if (target != Display.STATE_ON) { - return; - } - // If display state changed to on, proceed and stop the color fade and turn screen on. - mPendingScreenOff = false; - } - - if (mDisplayBlanksAfterDozeConfig - && Display.isDozeState(mPowerState.getScreenState()) - && !Display.isDozeState(target)) { - // Skip the screen off animation and add a black surface to hide the - // contents of the screen. - mPowerState.prepareColorFade(mContext, - mColorFadeFadesConfig ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP); - if (mColorFadeOffAnimator != null) { - mColorFadeOffAnimator.end(); - } - // Some display hardware will blank itself on the transition between doze and non-doze - // but still on display states. In this case we want to report to policy that the - // display has turned off so it can prepare the appropriate power on animation, but we - // don't want to actually transition to the fully off state since that takes - // significantly longer to transition from. - setScreenState(Display.STATE_OFF, target != Display.STATE_OFF /*reportOnly*/); - } - - // If we were in the process of turning off the screen but didn't quite - // finish. Then finish up now to prevent a jarring transition back - // to screen on if we skipped blocking screen on as usual. - if (mPendingScreenOff && target != Display.STATE_OFF) { - setScreenState(Display.STATE_OFF); - mPendingScreenOff = false; - mPowerState.dismissColorFadeResources(); - } - - if (target == Display.STATE_ON) { - // Want screen on. The contents of the screen may not yet - // be visible if the color fade has not been dismissed because - // its last frame of animation is solid black. - if (!setScreenState(Display.STATE_ON)) { - return; // screen on blocked - } - if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) { - // Perform screen on animation. - if (mPowerState.getColorFadeLevel() == 1.0f) { - mPowerState.dismissColorFade(); - } else if (mPowerState.prepareColorFade(mContext, - mColorFadeFadesConfig - ? ColorFade.MODE_FADE : ColorFade.MODE_WARM_UP)) { - mColorFadeOnAnimator.start(); - } else { - mColorFadeOnAnimator.end(); - } - } else { - // Skip screen on animation. - mPowerState.setColorFadeLevel(1.0f); - mPowerState.dismissColorFade(); - } - } else if (target == Display.STATE_DOZE) { - // Want screen dozing. - // Wait for brightness animation to complete beforehand when entering doze - // from screen on to prevent a perceptible jump because brightness may operate - // differently when the display is configured for dozing. - if (mScreenBrightnessRampAnimator.isAnimating() - && mPowerState.getScreenState() == Display.STATE_ON) { - return; - } - - // Set screen state. - if (!setScreenState(Display.STATE_DOZE)) { - return; // screen on blocked - } - - // Dismiss the black surface without fanfare. - mPowerState.setColorFadeLevel(1.0f); - mPowerState.dismissColorFade(); - } else if (target == Display.STATE_DOZE_SUSPEND) { - // Want screen dozing and suspended. - // Wait for brightness animation to complete beforehand unless already - // suspended because we may not be able to change it after suspension. - if (mScreenBrightnessRampAnimator.isAnimating() - && mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) { - return; - } - - // If not already suspending, temporarily set the state to doze until the - // screen on is unblocked, then suspend. - if (mPowerState.getScreenState() != Display.STATE_DOZE_SUSPEND) { - if (!setScreenState(Display.STATE_DOZE)) { - return; // screen on blocked - } - setScreenState(Display.STATE_DOZE_SUSPEND); // already on so can't block - } - - // Dismiss the black surface without fanfare. - mPowerState.setColorFadeLevel(1.0f); - mPowerState.dismissColorFade(); - } else if (target == Display.STATE_ON_SUSPEND) { - // Want screen full-power and suspended. - // Wait for brightness animation to complete beforehand unless already - // suspended because we may not be able to change it after suspension. - if (mScreenBrightnessRampAnimator.isAnimating() - && mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) { - return; - } - - // If not already suspending, temporarily set the state to on until the - // screen on is unblocked, then suspend. - if (mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) { - if (!setScreenState(Display.STATE_ON)) { - return; - } - setScreenState(Display.STATE_ON_SUSPEND); - } - - // Dismiss the black surface without fanfare. - mPowerState.setColorFadeLevel(1.0f); - mPowerState.dismissColorFade(); - } else { - // Want screen off. - mPendingScreenOff = true; - if (!mColorFadeEnabled) { - mPowerState.setColorFadeLevel(0.0f); - } - - if (mPowerState.getColorFadeLevel() == 0.0f) { - // Turn the screen off. - // A black surface is already hiding the contents of the screen. - setScreenState(Display.STATE_OFF); - mPendingScreenOff = false; - mPowerState.dismissColorFadeResources(); - } else if (performScreenOffTransition - && mPowerState.prepareColorFade(mContext, - mColorFadeFadesConfig - ? ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN) - && mPowerState.getScreenState() != Display.STATE_OFF) { - // Perform the screen off animation. - mColorFadeOffAnimator.start(); - } else { - // Skip the screen off animation and add a black surface to hide the - // contents of the screen. - mColorFadeOffAnimator.end(); - } - } - } - - private final Runnable mCleanListener = this::sendUpdatePowerState; - - private void sendOnStateChangedWithWakelock() { - boolean wakeLockAcquired = mWakelockController.acquireWakelock( - WakelockController.WAKE_LOCK_STATE_CHANGED); - if (wakeLockAcquired) { - mHandler.post(mWakelockController.getOnStateChangedRunnable()); - } - } - - private void logDisplayPolicyChanged(int newPolicy) { - LogMaker log = new LogMaker(MetricsEvent.DISPLAY_POLICY); - log.setType(MetricsEvent.TYPE_UPDATE); - log.setSubtype(newPolicy); - MetricsLogger.action(log); - } - - private void handleSettingsChange(boolean userSwitch) { - mDisplayBrightnessController - .setPendingScreenBrightness(mDisplayBrightnessController - .getScreenBrightnessSetting()); - mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(userSwitch); - if (userSwitch) { - // Don't treat user switches as user initiated change. - mDisplayBrightnessController - .setAndNotifyCurrentScreenBrightness(mDisplayBrightnessController - .getPendingScreenBrightness()); - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.resetShortTermModel(); - } - } - sendUpdatePowerState(); - } - - private void handleBrightnessModeChange() { - final int screenBrightnessModeSetting = Settings.System.getIntForUser( - mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); - mHandler.postAtTime(() -> { - mAutomaticBrightnessStrategy.setUseAutoBrightness(screenBrightnessModeSetting - == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - updatePowerState(); - }, mClock.uptimeMillis()); - } - - - @Override - public float getScreenBrightnessSetting() { - return mDisplayBrightnessController.getScreenBrightnessSetting(); - } - - @Override - public void setBrightness(float brightnessValue, int userSerial) { - mDisplayBrightnessController.setBrightness(clampScreenBrightness(brightnessValue), - userSerial); - } - - @Override - public int getDisplayId() { - return mDisplayId; - } - - @Override - public int getLeadDisplayId() { - return mLeadDisplayId; - } - - @Override - public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux, - boolean slowChange) { - mBrightnessRangeController.onAmbientLuxChange(ambientLux); - if (nits == BrightnessMappingStrategy.INVALID_NITS) { - mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, slowChange); - } else { - float brightness = mDisplayBrightnessController.getBrightnessFromNits(nits); - if (BrightnessUtils.isValidBrightnessValue(brightness)) { - mDisplayBrightnessController.setBrightnessToFollow(brightness, slowChange); - } else { - // The device does not support nits - mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, - slowChange); - } - } - sendUpdatePowerState(); - } - - private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated, - boolean wasShortTermModelActive, boolean autobrightnessEnabled, - boolean brightnessIsTemporary, boolean shouldUseAutoBrightness) { - - final float brightnessInNits = - mDisplayBrightnessController.convertToAdjustedNits(brightness); - // Don't report brightness to brightnessTracker: - // If brightness is temporary (ie the slider has not been released) - // or if we are in idle screen brightness mode. - // or display is not on - // or we shouldn't be using autobrightness - // or the nits is invalid. - if (brightnessIsTemporary - || mAutomaticBrightnessController == null - || mAutomaticBrightnessController.isInIdleMode() - || !autobrightnessEnabled - || mBrightnessTracker == null - || !shouldUseAutoBrightness - || brightnessInNits < 0.0f) { - return; - } - - if (userInitiated && (mAutomaticBrightnessController == null - || !mAutomaticBrightnessController.hasValidAmbientLux())) { - // If we don't have a valid lux reading we can't report a valid - // slider event so notify as if the system changed the brightness. - userInitiated = false; - } - - // We only want to track changes on devices that can actually map the display backlight - // values into a physical brightness unit since the value provided by the API is in - // nits and not using the arbitrary backlight units. - final float powerFactor = mPowerRequest.lowPowerMode - ? mPowerRequest.screenLowPowerBrightnessFactor - : 1.0f; - mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated, - powerFactor, wasShortTermModelActive, - mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId, - mAutomaticBrightnessController.getLastSensorValues(), - mAutomaticBrightnessController.getLastSensorTimestamps()); - } - - @Override - public void addDisplayBrightnessFollower(DisplayPowerControllerInterface follower) { - synchronized (mLock) { - mDisplayBrightnessFollowers.append(follower.getDisplayId(), follower); - sendUpdatePowerStateLocked(); - } - } - - @Override - public void removeDisplayBrightnessFollower(DisplayPowerControllerInterface follower) { - synchronized (mLock) { - mDisplayBrightnessFollowers.remove(follower.getDisplayId()); - mHandler.postAtTime(() -> follower.setBrightnessToFollow( - PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, - /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); - } - } - - @GuardedBy("mLock") - private void clearDisplayBrightnessFollowersLocked() { - for (int i = 0; i < mDisplayBrightnessFollowers.size(); i++) { - DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i); - mHandler.postAtTime(() -> follower.setBrightnessToFollow( - PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS, - /* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis()); - } - mDisplayBrightnessFollowers.clear(); - } - - @Override - public void dump(final PrintWriter pw) { - synchronized (mLock) { - pw.println(); - pw.println("Display Power Controller:"); - pw.println(" mDisplayId=" + mDisplayId); - pw.println(" mLeadDisplayId=" + mLeadDisplayId); - pw.println(" mLightSensor=" + mLightSensor); - pw.println(" mDisplayBrightnessFollowers=" + mDisplayBrightnessFollowers); - - pw.println(); - pw.println("Display Power Controller Locked State:"); - pw.println(" mDisplayReadyLocked=" + mDisplayReadyLocked); - pw.println(" mPendingRequestLocked=" + mPendingRequestLocked); - pw.println(" mPendingRequestChangedLocked=" + mPendingRequestChangedLocked); - pw.println(" mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked); - } - - pw.println(); - pw.println("Display Power Controller Configuration:"); - pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig); - pw.println(" mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig); - pw.println(" mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp); - pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig); - pw.println(" mColorFadeEnabled=" + mColorFadeEnabled); - pw.println(" mIsDisplayInternal=" + mIsDisplayInternal); - synchronized (mCachedBrightnessInfo) { - pw.println(" mCachedBrightnessInfo.brightness=" - + mCachedBrightnessInfo.brightness.value); - pw.println(" mCachedBrightnessInfo.adjustedBrightness=" - + mCachedBrightnessInfo.adjustedBrightness.value); - pw.println(" mCachedBrightnessInfo.brightnessMin=" - + mCachedBrightnessInfo.brightnessMin.value); - pw.println(" mCachedBrightnessInfo.brightnessMax=" - + mCachedBrightnessInfo.brightnessMax.value); - pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value); - pw.println(" mCachedBrightnessInfo.hbmTransitionPoint=" - + mCachedBrightnessInfo.hbmTransitionPoint.value); - pw.println(" mCachedBrightnessInfo.brightnessMaxReason =" - + mCachedBrightnessInfo.brightnessMaxReason.value); - } - pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig); - pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig); - mHandler.runWithScissors(() -> dumpLocal(pw), 1000); - } - - private void dumpLocal(PrintWriter pw) { - pw.println(); - pw.println("Display Power Controller Thread State:"); - pw.println(" mPowerRequest=" + mPowerRequest); - pw.println(" mBrightnessReason=" + mBrightnessReason); - pw.println(" mAppliedDimming=" + mAppliedDimming); - pw.println(" mAppliedThrottling=" + mAppliedThrottling); - pw.println(" mDozing=" + mDozing); - pw.println(" mSkipRampState=" + skipRampStateToString(mSkipRampState)); - pw.println(" mScreenOnBlockStartRealTime=" + mScreenOnBlockStartRealTime); - pw.println(" mScreenOffBlockStartRealTime=" + mScreenOffBlockStartRealTime); - pw.println(" mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker); - pw.println(" mPendingScreenOffUnblocker=" + mPendingScreenOffUnblocker); - pw.println(" mPendingScreenOff=" + mPendingScreenOff); - pw.println(" mReportedToPolicy=" - + reportedToPolicyToString(mReportedScreenStateToPolicy)); - pw.println(" mIsRbcActive=" + mIsRbcActive); - IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); - mAutomaticBrightnessStrategy.dump(ipw); - - if (mScreenBrightnessRampAnimator != null) { - pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" - + mScreenBrightnessRampAnimator.isAnimating()); - } - - if (mColorFadeOnAnimator != null) { - pw.println(" mColorFadeOnAnimator.isStarted()=" - + mColorFadeOnAnimator.isStarted()); - } - if (mColorFadeOffAnimator != null) { - pw.println(" mColorFadeOffAnimator.isStarted()=" - + mColorFadeOffAnimator.isStarted()); - } - - if (mPowerState != null) { - mPowerState.dump(pw); - } - - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.dump(pw); - dumpBrightnessEvents(pw); - } - - dumpRbcEvents(pw); - - if (mScreenOffBrightnessSensorController != null) { - mScreenOffBrightnessSensorController.dump(pw); - } - - if (mBrightnessRangeController != null) { - mBrightnessRangeController.dump(pw); - } - - if (mBrightnessThrottler != null) { - mBrightnessThrottler.dump(pw); - } - - pw.println(); - if (mDisplayWhiteBalanceController != null) { - mDisplayWhiteBalanceController.dump(pw); - mDisplayWhiteBalanceSettings.dump(pw); - } - - pw.println(); - - if (mWakelockController != null) { - mWakelockController.dumpLocal(pw); - } - - pw.println(); - if (mDisplayBrightnessController != null) { - mDisplayBrightnessController.dump(pw); - } - - pw.println(); - if (mDisplayStateController != null) { - mDisplayStateController.dumpsys(pw); - } - - pw.println(); - if (mBrightnessClamperController != null) { - mBrightnessClamperController.dump(ipw); - } - } - - - private static String reportedToPolicyToString(int state) { - switch (state) { - case REPORTED_TO_POLICY_SCREEN_OFF: - return "REPORTED_TO_POLICY_SCREEN_OFF"; - case REPORTED_TO_POLICY_SCREEN_TURNING_ON: - return "REPORTED_TO_POLICY_SCREEN_TURNING_ON"; - case REPORTED_TO_POLICY_SCREEN_ON: - return "REPORTED_TO_POLICY_SCREEN_ON"; - default: - return Integer.toString(state); - } - } - - private static String skipRampStateToString(int state) { - switch (state) { - case RAMP_STATE_SKIP_NONE: - return "RAMP_STATE_SKIP_NONE"; - case RAMP_STATE_SKIP_INITIAL: - return "RAMP_STATE_SKIP_INITIAL"; - case RAMP_STATE_SKIP_AUTOBRIGHT: - return "RAMP_STATE_SKIP_AUTOBRIGHT"; - default: - return Integer.toString(state); - } - } - - private void dumpBrightnessEvents(PrintWriter pw) { - int size = mBrightnessEventRingBuffer.size(); - if (size < 1) { - pw.println("No Automatic Brightness Adjustments"); - return; - } - - pw.println("Automatic Brightness Adjustments Last " + size + " Events: "); - BrightnessEvent[] eventArray = mBrightnessEventRingBuffer.toArray(); - for (int i = 0; i < mBrightnessEventRingBuffer.size(); i++) { - pw.println(" " + eventArray[i].toString()); - } - } - - private void dumpRbcEvents(PrintWriter pw) { - int size = mRbcEventRingBuffer.size(); - if (size < 1) { - pw.println("No Reduce Bright Colors Adjustments"); - return; - } - - pw.println("Reduce Bright Colors Adjustments Last " + size + " Events: "); - BrightnessEvent[] eventArray = mRbcEventRingBuffer.toArray(); - for (int i = 0; i < mRbcEventRingBuffer.size(); i++) { - pw.println(" " + eventArray[i]); - } - } - - - private void noteScreenState(int screenState) { - // Log screen state change with display id - FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_STATE_CHANGED_V2, - screenState, mDisplayStatsId); - if (mBatteryStats != null) { - try { - // TODO(multi-display): make this multi-display - mBatteryStats.noteScreenState(screenState); - } catch (RemoteException e) { - // same process - } - } - } - - @SuppressLint("AndroidFrameworkRequiresPermission") - private void noteScreenBrightness(float brightness) { - if (mBatteryStats != null) { - try { - // TODO(brightnessfloat): change BatteryStats to use float - int brightnessInt = mFlags.isBrightnessIntRangeUserPerceptionEnabled() - ? BrightnessSynchronizer.brightnessFloatToIntSetting(mContext, brightness) - : BrightnessSynchronizer.brightnessFloatToInt(brightness); - mBatteryStats.noteScreenBrightness(brightnessInt); - } catch (RemoteException e) { - // same process - } - } - } - - private void reportStats(float brightness) { - if (mLastStatsBrightness == brightness) { - return; - } - - float hbmTransitionPoint = PowerManager.BRIGHTNESS_MAX; - synchronized (mCachedBrightnessInfo) { - if (mCachedBrightnessInfo.hbmTransitionPoint == null) { - return; - } - hbmTransitionPoint = mCachedBrightnessInfo.hbmTransitionPoint.value; - } - - final boolean aboveTransition = brightness > hbmTransitionPoint; - final boolean oldAboveTransition = mLastStatsBrightness > hbmTransitionPoint; - - if (aboveTransition || oldAboveTransition) { - mLastStatsBrightness = brightness; - mHandler.removeMessages(MSG_STATSD_HBM_BRIGHTNESS); - if (aboveTransition != oldAboveTransition) { - // report immediately - logHbmBrightnessStats(brightness, mDisplayStatsId); - } else { - // delay for rate limiting - Message msg = mHandler.obtainMessage(); - msg.what = MSG_STATSD_HBM_BRIGHTNESS; - msg.arg1 = Float.floatToIntBits(brightness); - msg.arg2 = mDisplayStatsId; - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis() - + BRIGHTNESS_CHANGE_STATSD_REPORT_INTERVAL_MS); - } - } - } - - private void logHbmBrightnessStats(float brightness, int displayStatsId) { - synchronized (mHandler) { - FrameworkStatsLog.write( - FrameworkStatsLog.DISPLAY_HBM_BRIGHTNESS_CHANGED, displayStatsId, brightness); - } - } - - // Return bucket index of range_[left]_[right] where - // left <= nits < right - private int nitsToRangeIndex(float nits) { - for (int i = 0; i < BRIGHTNESS_RANGE_BOUNDARIES.length; i++) { - if (nits < BRIGHTNESS_RANGE_BOUNDARIES[i]) { - return BRIGHTNESS_RANGE_INDEX[i]; - } - } - return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__BUCKET_INDEX__RANGE_3000_INF; - } - - private int convertBrightnessReasonToStatsEnum(int brightnessReason) { - switch(brightnessReason) { - case BrightnessReason.REASON_UNKNOWN: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; - case BrightnessReason.REASON_MANUAL: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_MANUAL; - case BrightnessReason.REASON_DOZE: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE; - case BrightnessReason.REASON_DOZE_DEFAULT: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_DOZE_DEFAULT; - case BrightnessReason.REASON_AUTOMATIC: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_AUTOMATIC; - case BrightnessReason.REASON_SCREEN_OFF: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF; - case BrightnessReason.REASON_OVERRIDE: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_OVERRIDE; - case BrightnessReason.REASON_TEMPORARY: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_TEMPORARY; - case BrightnessReason.REASON_BOOST: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_BOOST; - case BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_SCREEN_OFF_BRIGHTNESS_SENSOR; - case BrightnessReason.REASON_FOLLOWER: - return FrameworkStatsLog - .DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_FOLLOWER; - } - return FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__ENTIRE_REASON__REASON_UNKNOWN; - } - - private void logBrightnessEvent(BrightnessEvent event, float unmodifiedBrightness) { - int modifier = event.getReason().getModifier(); - int flags = event.getFlags(); - // It's easier to check if the brightness is at maximum level using the brightness - // value untouched by any modifiers - boolean brightnessIsMax = unmodifiedBrightness == event.getHbmMax(); - float brightnessInNits = - mDisplayBrightnessController.convertToAdjustedNits(event.getBrightness()); - float appliedLowPowerMode = event.isLowPowerModeSet() ? event.getPowerFactor() : -1f; - int appliedRbcStrength = event.isRbcEnabled() ? event.getRbcStrength() : -1; - float appliedHbmMaxNits = - event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF - ? -1f : mDisplayBrightnessController.convertToAdjustedNits(event.getHbmMax()); - // thermalCapNits set to -1 if not currently capping max brightness - float appliedThermalCapNits = - event.getThermalMax() == PowerManager.BRIGHTNESS_MAX - ? -1f : mDisplayBrightnessController.convertToAdjustedNits(event.getThermalMax()); - if (mIsDisplayInternal) { - FrameworkStatsLog.write(FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED, - mDisplayBrightnessController - .convertToAdjustedNits(event.getInitialBrightness()), - brightnessInNits, - event.getLux(), - event.getPhysicalDisplayId(), - event.wasShortTermModelActive(), - appliedLowPowerMode, - appliedRbcStrength, - appliedHbmMaxNits, - appliedThermalCapNits, - event.isAutomaticBrightnessEnabled(), - FrameworkStatsLog.DISPLAY_BRIGHTNESS_CHANGED__REASON__REASON_MANUAL, - convertBrightnessReasonToStatsEnum(event.getReason().getReason()), - nitsToRangeIndex(brightnessInNits), - brightnessIsMax, - event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, - event.getHbmMode() == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, - (modifier & BrightnessReason.MODIFIER_LOW_POWER) > 0, - mBrightnessClamperController.getBrightnessMaxReason(), - // TODO: (flc) add brightnessMinReason here too. - (modifier & BrightnessReason.MODIFIER_DIMMED) > 0, - event.isRbcEnabled(), - (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0, - (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0, - (flags & BrightnessEvent.FLAG_USER_SET) > 0, - (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0, - (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0); - } - } - - /** - * Indicates whether the display state is ready to update. If this is the default display, we - * want to update it right away so that we can draw the boot animation on it. If it is not - * the default display, drawing the boot animation on it would look incorrect, so we need - * to wait until boot is completed. - * @return True if the display state is ready to update - */ - private boolean readyToUpdateDisplayState() { - return mDisplayId == Display.DEFAULT_DISPLAY || mBootCompleted; - } - - private final class DisplayControllerHandler extends Handler { - DisplayControllerHandler(Looper looper) { - super(looper, null, true /*async*/); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE_POWER_STATE: - updatePowerState(); - break; - - case MSG_SCREEN_ON_UNBLOCKED: - if (mPendingScreenOnUnblocker == msg.obj) { - unblockScreenOn(); - updatePowerState(); - } - break; - case MSG_SCREEN_OFF_UNBLOCKED: - if (mPendingScreenOffUnblocker == msg.obj) { - unblockScreenOff(); - updatePowerState(); - } - break; - case MSG_OFFLOADING_SCREEN_ON_UNBLOCKED: - if (mDisplayOffloadSession == msg.obj) { - unblockScreenOnByDisplayOffload(); - updatePowerState(); - } - break; - case MSG_CONFIGURE_BRIGHTNESS: - BrightnessConfiguration brightnessConfiguration = - (BrightnessConfiguration) msg.obj; - mAutomaticBrightnessStrategy.setBrightnessConfiguration(brightnessConfiguration, - msg.arg1 == 1); - if (mBrightnessTracker != null) { - mBrightnessTracker - .setShouldCollectColorSample(brightnessConfiguration != null - && brightnessConfiguration.shouldCollectColorSamples()); - } - updatePowerState(); - break; - - case MSG_SET_TEMPORARY_BRIGHTNESS: - // TODO: Should we have a a timeout for the temporary brightness? - mDisplayBrightnessController - .setTemporaryBrightness(Float.intBitsToFloat(msg.arg1)); - updatePowerState(); - break; - - case MSG_SET_TEMPORARY_AUTO_BRIGHTNESS_ADJUSTMENT: - mAutomaticBrightnessStrategy - .setTemporaryAutoBrightnessAdjustment(Float.intBitsToFloat(msg.arg1)); - updatePowerState(); - break; - - case MSG_STOP: - cleanupHandlerThreadAfterStop(); - break; - - case MSG_UPDATE_BRIGHTNESS: - if (mStopped) { - return; - } - handleSettingsChange(false /*userSwitch*/); - break; - - case MSG_UPDATE_RBC: - handleRbcChanged(); - break; - - case MSG_BRIGHTNESS_RAMP_DONE: - if (mPowerState != null) { - final float brightness = mPowerState.getScreenBrightness(); - reportStats(brightness); - } - break; - - case MSG_STATSD_HBM_BRIGHTNESS: - logHbmBrightnessStats(Float.intBitsToFloat(msg.arg1), msg.arg2); - break; - - case MSG_SWITCH_USER: - handleOnSwitchUser(msg.arg1); - break; - - case MSG_BOOT_COMPLETED: - mBootCompleted = true; - updatePowerState(); - break; - - case MSG_SET_DWBC_STRONG_MODE: - setDwbcStrongMode(msg.arg1); - break; - - case MSG_SET_DWBC_COLOR_OVERRIDE: - final float cct = Float.intBitsToFloat(msg.arg1); - setDwbcOverride(cct); - break; - - case MSG_SET_DWBC_LOGGING_ENABLED: - setDwbcLoggingEnabled(msg.arg1); - break; - case MSG_SET_BRIGHTNESS_FROM_OFFLOAD: - mDisplayBrightnessController.setBrightnessFromOffload( - Float.intBitsToFloat(msg.arg1)); - updatePowerState(); - break; - } - } - } - - - private final class SettingsObserver extends ContentObserver { - SettingsObserver(Handler handler) { - super(handler); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE))) { - handleBrightnessModeChange(); - } else if (uri.equals(Settings.System.getUriFor( - Settings.System.SCREEN_BRIGHTNESS_FOR_ALS))) { - int preset = Settings.System.getIntForUser(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_FOR_ALS, - Settings.System.SCREEN_BRIGHTNESS_AUTOMATIC_NORMAL, - UserHandle.USER_CURRENT); - Slog.i(mTag, "Setting up auto-brightness for preset " - + autoBrightnessPresetToString(preset)); - setUpAutoBrightness(mContext, mHandler); - sendUpdatePowerState(); - } else { - handleSettingsChange(false /* userSwitch */); - } - } - } - - private final class ScreenOnUnblocker implements WindowManagerPolicy.ScreenOnListener { - @Override - public void onScreenOn() { - Message msg = mHandler.obtainMessage(MSG_SCREEN_ON_UNBLOCKED, this); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - } - - private final class ScreenOffUnblocker implements WindowManagerPolicy.ScreenOffListener { - @Override - public void onScreenOff() { - Message msg = mHandler.obtainMessage(MSG_SCREEN_OFF_UNBLOCKED, this); - mHandler.sendMessageAtTime(msg, mClock.uptimeMillis()); - } - } - - @Override - public void setAutoBrightnessLoggingEnabled(boolean enabled) { - if (mAutomaticBrightnessController != null) { - mAutomaticBrightnessController.setLoggingEnabled(enabled); - } - } - - @Override // DisplayWhiteBalanceController.Callbacks - public void updateWhiteBalance() { - sendUpdatePowerState(); - } - - @Override - public void setDisplayWhiteBalanceLoggingEnabled(boolean enabled) { - Message msg = mHandler.obtainMessage(); - msg.what = MSG_SET_DWBC_LOGGING_ENABLED; - msg.arg1 = enabled ? 1 : 0; - msg.sendToTarget(); - } - - @Override - public void setAmbientColorTemperatureOverride(float cct) { - Message msg = mHandler.obtainMessage(); - msg.what = MSG_SET_DWBC_COLOR_OVERRIDE; - msg.arg1 = Float.floatToIntBits(cct); - msg.sendToTarget(); - } - - /** Functional interface for providing time. */ - @VisibleForTesting - interface Clock { - /** - * Returns current time in milliseconds since boot, not counting time spent in deep sleep. - */ - long uptimeMillis(); - } - - @VisibleForTesting - static class Injector { - Clock getClock() { - return SystemClock::uptimeMillis; - } - - DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, - int displayId, int displayState) { - return new DisplayPowerState(blanker, colorFade, displayId, displayState); - } - - DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps, - FloatProperty<DisplayPowerState> firstProperty, - FloatProperty<DisplayPowerState> secondProperty) { - return new DualRampAnimator(dps, firstProperty, secondProperty); - } - - WakelockController getWakelockController(int displayId, - DisplayPowerCallbacks displayPowerCallbacks) { - return new WakelockController(displayId, displayPowerCallbacks); - } - - DisplayPowerProximityStateController getDisplayPowerProximityStateController( - WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, - Looper looper, Runnable nudgeUpdatePowerState, - int displayId, SensorManager sensorManager) { - return new DisplayPowerProximityStateController(wakelockController, displayDeviceConfig, - looper, nudgeUpdatePowerState, - displayId, sensorManager, /* injector= */ null); - } - - AutomaticBrightnessController getAutomaticBrightnessController( - AutomaticBrightnessController.Callbacks callbacks, Looper looper, - SensorManager sensorManager, Sensor lightSensor, - SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, - int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, - float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, - long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, - long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, - boolean resetAmbientLuxAfterWarmUpConfig, - HysteresisLevels ambientBrightnessThresholds, - HysteresisLevels screenBrightnessThresholds, - HysteresisLevels ambientBrightnessThresholdsIdle, - HysteresisLevels screenBrightnessThresholdsIdle, Context context, - BrightnessRangeController brightnessModeController, - BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, - int ambientLightHorizonLong, float userLux, float userNits) { - return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor, - brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin, - brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate, - brighteningLightDebounceConfig, darkeningLightDebounceConfig, - brighteningLightDebounceConfigIdle, darkeningLightDebounceConfigIdle, - resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds, - screenBrightnessThresholds, ambientBrightnessThresholdsIdle, - screenBrightnessThresholdsIdle, context, brightnessModeController, - brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux, - userNits); - } - - BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context, - DisplayDeviceConfig displayDeviceConfig, - DisplayWhiteBalanceController displayWhiteBalanceController) { - return BrightnessMappingStrategy.create(context, displayDeviceConfig, - AUTO_BRIGHTNESS_MODE_DEFAULT, displayWhiteBalanceController); - } - - HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, - float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, - float[] darkeningThresholdLevels, float minDarkeningThreshold, - float minBrighteningThreshold) { - return new HysteresisLevels(brighteningThresholdsPercentages, - darkeningThresholdsPercentages, brighteningThresholdLevels, - darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold); - } - - HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, - float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, - float[] darkeningThresholdLevels, float minDarkeningThreshold, - float minBrighteningThreshold, boolean potentialOldBrightnessRange) { - return new HysteresisLevels(brighteningThresholdsPercentages, - darkeningThresholdsPercentages, brighteningThresholdLevels, - darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold, - potentialOldBrightnessRange); - } - - ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( - SensorManager sensorManager, - Sensor lightSensor, - Handler handler, - ScreenOffBrightnessSensorController.Clock clock, - int[] sensorValueToLux, - BrightnessMappingStrategy brightnessMapper) { - return new ScreenOffBrightnessSensorController( - sensorManager, - lightSensor, - handler, - clock, - sensorValueToLux, - brightnessMapper - ); - } - - HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width, - int height, IBinder displayToken, String displayUniqueId, float brightnessMin, - float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData, - HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg, - Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, - Context context) { - return new HighBrightnessModeController(handler, width, height, displayToken, - displayUniqueId, brightnessMin, brightnessMax, hbmData, hdrBrightnessCfg, - hbmChangeCallback, hbmMetadata, context); - } - - BrightnessRangeController getBrightnessRangeController( - HighBrightnessModeController hbmController, Runnable modeChangeCallback, - DisplayDeviceConfig displayDeviceConfig, Handler handler, - DisplayManagerFlags flags, IBinder displayToken, DisplayDeviceInfo info) { - return new BrightnessRangeController(hbmController, - modeChangeCallback, displayDeviceConfig, handler, flags, displayToken, info); - } - - BrightnessClamperController getBrightnessClamperController(Handler handler, - BrightnessClamperController.ClamperChangeListener clamperChangeListener, - BrightnessClamperController.DisplayDeviceData data, Context context, - DisplayManagerFlags flags) { - - return new BrightnessClamperController(handler, clamperChangeListener, data, context, - flags); - } - - DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, - SensorManager sensorManager, Resources resources) { - return DisplayWhiteBalanceFactory.create(handler, - sensorManager, resources); - } - - boolean isColorFadeEnabled() { - return !ActivityManager.isLowRamDeviceStatic(); - } - } - - static class CachedBrightnessInfo { - public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat adjustedBrightness = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat brightnessMin = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableFloat brightnessMax = - new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT); - public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); - public MutableFloat hbmTransitionPoint = - new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID); - public MutableInt brightnessMaxReason = - new MutableInt(BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE); - - public boolean checkAndSetFloat(MutableFloat mf, float f) { - if (mf.value != f) { - mf.value = f; - return true; - } - return false; - } - - public boolean checkAndSetInt(MutableInt mi, int i) { - if (mi.value != i) { - mi.value = i; - return true; - } - return false; - } - } -} diff --git a/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java index 465584c3d90c..403dfbe920ee 100644 --- a/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java +++ b/services/core/java/com/android/server/display/feature/DeviceConfigParameterProvider.java @@ -41,13 +41,6 @@ public class DeviceConfigParameterProvider { mDeviceConfig = deviceConfig; } - // feature: revamping_display_power_controller_feature - // parameter: use_newly_structured_display_power_controller - public boolean isNewPowerControllerFeatureEnabled() { - return mDeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, - DisplayManager.DeviceConfig.KEY_NEW_POWER_CONTROLLER, true); - } - // feature: hdr_output_control // parameter: enable_hdr_output_control public boolean isHdrOutputControlFeatureEnabled() { diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index c9569cbf4b9a..a2319a8a7c07 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -109,7 +109,7 @@ flag { name: "back_up_smooth_display_and_force_peak_refresh_rate" namespace: "display_manager" description: "Feature flag for backing up Smooth Display and Force Peak Refresh Rate" - bug: "211737588" + bug: "299552529" is_fixed_read_only: true } @@ -125,7 +125,7 @@ flag { name: "brightness_int_range_user_perception" namespace: "display_manager" description: "Feature flag for converting the brightness integer range to the user perception scale" - bug: "183655602" + bug: "319236956" is_fixed_read_only: true } diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java index 50e953323443..ad3deffb9590 100644 --- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java @@ -22,7 +22,6 @@ import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE; -import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.annotation.IntegerRes; import android.annotation.NonNull; @@ -238,8 +237,11 @@ public class DisplayModeDirector { * is ready. */ public void start(SensorManager sensorManager) { - mSettingsObserver.observe(); + // This has to be called first to read the supported display modes that will be used by + // other observers mDisplayObserver.observe(); + + mSettingsObserver.observe(); mBrightnessObserver.observe(sensorManager); mSensorObserver.observe(); mHbmObserver.observe(); @@ -620,11 +622,16 @@ public class DisplayModeDirector { } @VisibleForTesting + DisplayObserver getDisplayObserver() { + return mDisplayObserver; + } + + @VisibleForTesting DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings( float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { synchronized (mLock) { - mSettingsObserver.updateRefreshRateSettingLocked( - minRefreshRate, peakRefreshRate, defaultRefreshRate); + mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, + defaultRefreshRate, Display.DEFAULT_DISPLAY); return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY); } } @@ -897,19 +904,17 @@ public class DisplayModeDirector { if (defaultPeakRefreshRate == null) { setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig, /* attemptReadFromFeatureParams= */ false); - updateRefreshRateSettingLocked(); } else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) { mDefaultPeakRefreshRate = defaultPeakRefreshRate; - updateRefreshRateSettingLocked(); } + updateRefreshRateSettingLocked(); } } @Override public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { - if (mPeakRefreshRateSetting.equals(uri) - || mMinRefreshRateSetting.equals(uri)) { + if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) { updateRefreshRateSettingLocked(); } else if (mLowPowerModeSetting.equals(uri)) { updateLowPowerModeSettingLocked(); @@ -969,9 +974,29 @@ public class DisplayModeDirector { mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode); } + /** + * Update refresh rate settings for all displays + */ + @GuardedBy("mLock") private void updateRefreshRateSettingLocked() { + for (int i = 0; i < mSupportedModesByDisplay.size(); i++) { + updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i)); + } + } + + /** + * Update refresh rate settings for a specific display + * @param displayId The display ID + */ + @GuardedBy("mLock") + private void updateRefreshRateSettingLocked(int displayId) { final ContentResolver cr = mContext.getContentResolver(); - float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext); + if (!mSupportedModesByDisplay.contains(displayId)) { + Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display " + + displayId); + return; + } + float highestRefreshRate = getMaxRefreshRateLocked(displayId); float minRefreshRate = Settings.System.getFloatForUser(cr, Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId()); @@ -1009,11 +1034,13 @@ public class DisplayModeDirector { Float.POSITIVE_INFINITY, cr.getUserId()); } - updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate); + updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate, + displayId); } - private void updateRefreshRateSettingLocked( - float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) { + @GuardedBy("mLock") + private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate, + float defaultRefreshRate, int displayId) { // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is // used to predict if we're going to be doing frequent refresh rate switching, and if // so, enable the brightness observer. The logic here is more complicated and fragile @@ -1021,9 +1048,9 @@ public class DisplayModeDirector { Vote peakVote = peakRefreshRate == 0f ? null : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate)); - mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, + mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, peakVote); - mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, + mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY)); Vote defaultVote = defaultRefreshRate == 0f @@ -1050,6 +1077,14 @@ public class DisplayModeDirector { mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate); } + private void removeRefreshRateSetting(int displayId) { + mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE, + null); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE, + null); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null); + } + private void updateModeSwitchingTypeSettingLocked() { final ContentResolver cr = mContext.getContentResolver(); int switchingType = Settings.Secure.getIntForUser( @@ -1180,7 +1215,8 @@ public class DisplayModeDirector { } } - private final class DisplayObserver implements DisplayManager.DisplayListener { + @VisibleForTesting + public final class DisplayObserver implements DisplayManager.DisplayListener { // Note that we can never call into DisplayManager or any of the non-POD classes it // returns, while holding mLock since it may call into DMS, which might be simultaneously // calling into us already holding its own lock. @@ -1227,11 +1263,10 @@ public class DisplayModeDirector { // Populate existing displays SparseArray<Display.Mode[]> modes = new SparseArray<>(); SparseArray<Display.Mode> defaultModes = new SparseArray<>(); - DisplayInfo info = new DisplayInfo(); Display[] displays = mInjector.getDisplays(); for (Display d : displays) { final int displayId = d.getDisplayId(); - d.getDisplayInfo(info); + DisplayInfo info = getDisplayInfo(displayId); modes.put(displayId, info.supportedModes); defaultModes.put(displayId, info.getDefaultMode()); } @@ -1259,6 +1294,7 @@ public class DisplayModeDirector { synchronized (mLock) { mSupportedModesByDisplay.remove(displayId); mDefaultModeByDisplay.remove(displayId); + mSettingsObserver.removeRefreshRateSetting(displayId); } updateLayoutLimitedFrameRate(displayId, null); removeUserSettingDisplayPreferredSize(displayId); @@ -1409,6 +1445,7 @@ public class DisplayModeDirector { } if (changed) { notifyDesiredDisplayModeSpecsChangedLocked(); + mSettingsObserver.updateRefreshRateSettingLocked(displayId); } } } diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java index 7e990c6c2f4a..380106ba486d 100644 --- a/services/core/java/com/android/server/input/InputManagerInternal.java +++ b/services/core/java/com/android/server/input/InputManagerInternal.java @@ -104,10 +104,13 @@ public abstract class InputManagerInternal { public abstract PointF getCursorPosition(); /** - * Sets the pointer acceleration. - * See {@code frameworks/native/include/input/VelocityControl.h#VelocityControlParameters}. + * Enables or disables pointer acceleration for mouse movements. + * + * Note that this only affects pointer movements from mice (that is, pointing devices which send + * relative motions, including trackballs and pointing sticks), not from other pointer devices + * such as touchpads and styluses. */ - public abstract void setPointerAcceleration(float acceleration, int displayId); + public abstract void setMousePointerAccelerationEnabled(boolean enabled, int displayId); /** * Sets the eligibility of windows on a given display for pointer capture. If a display is diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 36dac8316e54..bc7205ae2c07 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -64,7 +64,6 @@ import android.os.CombinedVibration; import android.os.Environment; import android.os.Handler; import android.os.IBinder; -import android.os.IInputConstants; import android.os.IVibratorStateListener; import android.os.InputEventInjectionResult; import android.os.InputEventInjectionSync; @@ -1372,9 +1371,9 @@ public class InputManagerService extends IInputManager.Stub mNative.setPointerSpeed(speed); } - private void setPointerAcceleration(float acceleration, int displayId) { + private void setMousePointerAccelerationEnabled(boolean enabled, int displayId) { updateAdditionalDisplayInputProperties(displayId, - properties -> properties.pointerAcceleration = acceleration); + properties -> properties.mousePointerAccelerationEnabled = enabled); } private void setPointerIconVisible(boolean visible, int displayId) { @@ -2261,7 +2260,8 @@ public class InputManagerService extends IInputManager.Stub + mAdditionalDisplayInputProperties.keyAt(i)); final AdditionalDisplayInputProperties properties = mAdditionalDisplayInputProperties.valueAt(i); - pw.println("pointerAcceleration: " + properties.pointerAcceleration); + pw.println("mousePointerAccelerationEnabled: " + + properties.mousePointerAccelerationEnabled); pw.println("pointerIconVisible: " + properties.pointerIconVisible); } pw.decreaseIndent(); @@ -3289,8 +3289,8 @@ public class InputManagerService extends IInputManager.Stub } @Override - public void setPointerAcceleration(float acceleration, int displayId) { - InputManagerService.this.setPointerAcceleration(acceleration, displayId); + public void setMousePointerAccelerationEnabled(boolean enabled, int displayId) { + InputManagerService.this.setMousePointerAccelerationEnabled(enabled, displayId); } @Override @@ -3382,11 +3382,15 @@ public class InputManagerService extends IInputManager.Stub private static class AdditionalDisplayInputProperties { static final boolean DEFAULT_POINTER_ICON_VISIBLE = true; - static final float DEFAULT_POINTER_ACCELERATION = - (float) IInputConstants.DEFAULT_POINTER_ACCELERATION; + static final boolean DEFAULT_MOUSE_POINTER_ACCELERATION_ENABLED = true; - // The pointer acceleration for this display. - public float pointerAcceleration; + /** + * Whether to enable mouse pointer acceleration on this display. Note that this only affects + * pointer movements from mice (that is, pointing devices which send relative motions, + * including trackballs and pointing sticks), not from other pointer devices such as + * touchpads and styluses. + */ + public boolean mousePointerAccelerationEnabled; // Whether the pointer icon should be visible or hidden on this display. public boolean pointerIconVisible; @@ -3396,12 +3400,12 @@ public class InputManagerService extends IInputManager.Stub } public boolean allDefaults() { - return Float.compare(pointerAcceleration, DEFAULT_POINTER_ACCELERATION) == 0 + return mousePointerAccelerationEnabled == DEFAULT_MOUSE_POINTER_ACCELERATION_ENABLED && pointerIconVisible == DEFAULT_POINTER_ICON_VISIBLE; } public void reset() { - pointerAcceleration = DEFAULT_POINTER_ACCELERATION; + mousePointerAccelerationEnabled = DEFAULT_MOUSE_POINTER_ACCELERATION_ENABLED; pointerIconVisible = DEFAULT_POINTER_ICON_VISIBLE; } } @@ -3433,9 +3437,11 @@ public class InputManagerService extends IInputManager.Stub } } - if (properties.pointerAcceleration != mCurrentDisplayProperties.pointerAcceleration) { - mCurrentDisplayProperties.pointerAcceleration = properties.pointerAcceleration; - mNative.setPointerAcceleration(properties.pointerAcceleration); + if (properties.mousePointerAccelerationEnabled + != mCurrentDisplayProperties.mousePointerAccelerationEnabled) { + mCurrentDisplayProperties.mousePointerAccelerationEnabled = + properties.mousePointerAccelerationEnabled; + mNative.setMousePointerAccelerationEnabled(properties.mousePointerAccelerationEnabled); } } diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 829b6607f113..dd9204cd1401 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -118,7 +118,7 @@ interface NativeInputManagerService { void setPointerSpeed(int speed); - void setPointerAcceleration(float acceleration); + void setMousePointerAccelerationEnabled(boolean enabled); void setTouchpadPointerSpeed(int speed); @@ -351,7 +351,7 @@ interface NativeInputManagerService { public native void setPointerSpeed(int speed); @Override - public native void setPointerAcceleration(float acceleration); + public native void setMousePointerAccelerationEnabled(boolean enabled); @Override public native void setTouchpadPointerSpeed(int speed); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 25ec6839efb5..4db9ead05636 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4869,8 +4869,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final List<ImeSubtypeListItem> imList = InputMethodSubtypeSwitchingController .getSortedInputMethodAndSubtypeList( - showAuxSubtypes, isScreenLocked, false, mContext, - mMethodMap, mSettings.getCurrentUserId()); + showAuxSubtypes, isScreenLocked, true /* forImeMenu */, + mContext, mMethodMap, mSettings.getCurrentUserId()); mMenuController.showInputMethodMenuLocked(showAuxSubtypes, displayId, lastInputMethodId, lastInputMethodSubtypeId, imList); } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java index fb57c09b9f73..58a68f2a0166 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java @@ -255,14 +255,6 @@ final class InputMethodUtils { return SecureSettingsWrapper.getInt(key, defaultValue, mCurrentUserId); } - private void putBoolean(String key, boolean value) { - SecureSettingsWrapper.putBoolean(key, value, mCurrentUserId); - } - - private boolean getBoolean(String key, boolean defaultValue) { - return SecureSettingsWrapper.getBoolean(key, defaultValue, mCurrentUserId); - } - ArrayList<InputMethodInfo> getEnabledInputMethodListLocked() { return getEnabledInputMethodListWithFilterLocked(null /* matchingCondition */); } diff --git a/services/core/java/com/android/server/inputmethod/OWNERS b/services/core/java/com/android/server/inputmethod/OWNERS index aa638aa49fb3..e507c6ba40a1 100644 --- a/services/core/java/com/android/server/inputmethod/OWNERS +++ b/services/core/java/com/android/server/inputmethod/OWNERS @@ -6,5 +6,8 @@ tarandeep@google.com fstern@google.com cosminbaies@google.com +# Automotive +kanant@google.com + ogunwale@google.com #{LAST_RESORT_SUGGESTION} jjaggi@google.com #{LAST_RESORT_SUGGESTION} 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 d02b6f4cff53..171fbb6f8a16 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -25,6 +25,7 @@ import static com.android.server.location.gnss.GnssManagerService.TAG; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.location.GnssMeasurement; import android.location.GnssMeasurementRequest; import android.location.GnssMeasurementsEvent; import android.location.IGnssMeasurementsListener; @@ -33,6 +34,7 @@ import android.os.IBinder; import android.stats.location.LocationStatsEnums; import android.util.Log; +import com.android.internal.annotations.GuardedBy; import com.android.server.location.gnss.GnssConfiguration.HalInterfaceVersion; import com.android.server.location.gnss.hal.GnssNative; import com.android.server.location.injector.AppOpsHelper; @@ -40,6 +42,8 @@ import com.android.server.location.injector.Injector; import com.android.server.location.injector.LocationUsageLogger; import com.android.server.location.injector.SettingsHelper; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.Collection; /** @@ -91,6 +95,9 @@ public final class GnssMeasurementsProvider extends private final LocationUsageLogger mLogger; private final GnssNative mGnssNative; + @GuardedBy("mMultiplexerLock") + private GnssMeasurementsEvent mLastGnssMeasurementsEvent; + public GnssMeasurementsProvider(Injector injector, GnssNative gnssNative) { super(injector); mAppOpsHelper = injector.getAppOpsHelper(); @@ -264,5 +271,46 @@ public final class GnssMeasurementsProvider extends return null; } }); + synchronized (mMultiplexerLock) { + mLastGnssMeasurementsEvent = event; + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + super.dump(fd, pw, args); + pw.print("last measurements="); + pw.println(getLastMeasurementEventSummary()); + } + + /** + * Returns a string of GnssMeasurementsEvent summary including received time, satellite count + * and average baseband C/No. + */ + private String getLastMeasurementEventSummary() { + synchronized (mMultiplexerLock) { + if (mLastGnssMeasurementsEvent == null) { + return null; + } + StringBuilder builder = new StringBuilder("["); + builder.append("elapsedRealtimeNs=").append( + mLastGnssMeasurementsEvent.getClock().getElapsedRealtimeNanos()); + builder.append(" measurementCount=").append( + mLastGnssMeasurementsEvent.getMeasurements().size()); + + float sumBasebandCn0 = 0; + int countBasebandCn0 = 0; + for (GnssMeasurement measurement : mLastGnssMeasurementsEvent.getMeasurements()) { + if (measurement.hasBasebandCn0DbHz()) { + sumBasebandCn0 += measurement.getBasebandCn0DbHz(); + countBasebandCn0++; + } + } + if (countBasebandCn0 > 0) { + builder.append(" avgBasebandCn0=").append(sumBasebandCn0 / countBasebandCn0); + } + builder.append("]"); + return builder.toString(); + } } } 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 c772e08b5f9f..5df0de83b567 100644 --- a/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java +++ b/services/core/java/com/android/server/location/injector/SystemEmergencyHelper.java @@ -22,12 +22,14 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.os.SystemClock; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.flags.Flags; import com.android.server.FgThread; import java.util.Objects; @@ -104,10 +106,26 @@ public class SystemEmergencyHelper extends EmergencyHelper { boolean isInExtensionTime = mEmergencyCallEndRealtimeMs != Long.MIN_VALUE && (SystemClock.elapsedRealtime() - mEmergencyCallEndRealtimeMs) < extensionTimeMs; - return mIsInEmergencyCall - || isInExtensionTime - || mTelephonyManager.getEmergencyCallbackMode() - || mTelephonyManager.isInEmergencySmsMode(); + if (!Flags.enforceTelephonyFeatureMapping()) { + return mIsInEmergencyCall + || isInExtensionTime + || mTelephonyManager.getEmergencyCallbackMode() + || mTelephonyManager.isInEmergencySmsMode(); + } else { + boolean emergencyCallbackMode = false; + boolean emergencySmsMode = false; + PackageManager pm = mContext.getPackageManager(); + if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)) { + emergencyCallbackMode = mTelephonyManager.getEmergencyCallbackMode(); + } + if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)) { + emergencySmsMode = mTelephonyManager.isInEmergencySmsMode(); + } + return mIsInEmergencyCall + || isInExtensionTime + || emergencyCallbackMode + || emergencySmsMode; + } } private class EmergencyCallTelephonyCallback extends TelephonyCallback implements diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index ad090829a2f6..542b3b06184a 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -52,6 +52,7 @@ import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYP import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.IActivityManager; @@ -74,6 +75,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.content.pm.UserProperties; import android.content.res.Resources; import android.database.ContentObserver; import android.database.sqlite.SQLiteDatabase; @@ -303,7 +305,7 @@ public class LockSettingsService extends ILockSettings.Stub { private boolean mThirdPartyAppsStarted; // Current password metrics for all secured users on the device. Updated when user unlocks the - // device or changes password. Removed when user is stopped. + // device or changes password. Removed if user is stopped with its CE key evicted. @GuardedBy("this") private final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>(); @VisibleForTesting @@ -793,13 +795,33 @@ public class LockSettingsService extends ILockSettings.Stub { } @VisibleForTesting + @RequiresPermission(anyOf = { + android.Manifest.permission.MANAGE_USERS, + android.Manifest.permission.QUERY_USERS, + android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) void onUserStopped(int userId) { hideEncryptionNotification(new UserHandle(userId)); - // User is stopped with its CE key evicted. Restore strong auth requirement to the default - // flags after boot since stopping and restarting a user later is equivalent to rebooting - // the device. + + // Normally, CE storage is locked when a user is stopped, and restarting the user requires + // strong auth. Therefore, reset the user's strong auth flags. The exception is users that + // allow delayed locking; under some circumstances, biometric authentication is allowed to + // restart such users. Don't reset the strong auth flags for such users. + // + // TODO(b/319142556): It might make more sense to reset the strong auth flags when CE + // storage is locked, instead of when the user is stopped. This would ensure the flags get + // reset if CE storage is locked later for a user that allows delayed locking. + if (android.os.Flags.allowPrivateProfile() + && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) { + UserProperties userProperties = mUserManager.getUserProperties(UserHandle.of(userId)); + if (userProperties != null && userProperties.getAllowStoppingUserWithDelayedLocking()) { + return; + } + } int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext); requireStrongAuth(strongAuthRequired, userId); + + // Don't keep the password metrics in memory for a stopped user that will require strong + // auth to start again, since strong auth will make the password metrics available again. synchronized (this) { mUserPasswordMetrics.remove(userId); } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 06a8d989b930..e048522eee53 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -774,7 +774,7 @@ class MediaRouter2ServiceImpl { .generateDeviceRouteSelectedSessionInfo(packageName); } else { sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos(); - if (sessionInfos != null && !sessionInfos.isEmpty()) { + if (!sessionInfos.isEmpty()) { // Return a copy of the current system session with no modification, // except setting the client package name. return new RoutingSessionInfo.Builder(sessionInfos.get(0)) @@ -1158,14 +1158,7 @@ class MediaRouter2ServiceImpl { } else { if (route.isSystemRoute() && !routerRecord.hasSystemRoutingPermission() - && !TextUtils.equals( - route.getId(), - routerRecord - .mUserRecord - .mHandler - .mSystemProvider - .getDefaultRoute() - .getId())) { + && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) { Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to" + route); routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter( @@ -1252,11 +1245,9 @@ class MediaRouter2ServiceImpl { "transferToRouteWithRouter2 | router: %s(id: %d), route: %s", routerRecord.mPackageName, routerRecord.mRouterId, route.getId())); - String defaultRouteId = - routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId(); if (route.isSystemRoute() && !routerRecord.hasSystemRoutingPermission() - && !TextUtils.equals(route.getId(), defaultRouteId)) { + && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) { routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::notifySessionCreationFailedToRouter, routerRecord.mUserRecord.mHandler, @@ -2761,11 +2752,10 @@ class MediaRouter2ServiceImpl { if (manager != null) { notifyRequestFailedToManager( manager.mManager, toOriginalRequestId(uniqueRequestId), reason); - return; } - // Currently, only the manager can get notified of failures. - // TODO: Notify router too when the related callback is introduced. + // Currently, only manager records can get notified of failures. + // TODO(b/282936553): Notify regular routers of request failures. } private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider, @@ -2909,11 +2899,9 @@ class MediaRouter2ServiceImpl { currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo(); } - if (currentRoutes.size() == 0) { - return; + if (!currentRoutes.isEmpty()) { + routerRecord.notifyRegistered(currentRoutes, currentSystemSessionInfo); } - - routerRecord.notifyRegistered(currentRoutes, currentSystemSessionInfo); } private static void notifyRoutesUpdatedToRouterRecords( diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 6deda468f9a2..f6571d94d554 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -653,14 +653,14 @@ public final class MediaProjectionManagerService extends SystemService } @Override // Binder call - public boolean hasProjectionPermission(int uid, String packageName) { + public boolean hasProjectionPermission(int processUid, String packageName) { final long token = Binder.clearCallingIdentity(); boolean hasPermission = false; try { hasPermission |= checkPermission(packageName, android.Manifest.permission.CAPTURE_VIDEO_OUTPUT) || mAppOps.noteOpNoThrow( - AppOpsManager.OP_PROJECT_MEDIA, uid, packageName) + AppOpsManager.OP_PROJECT_MEDIA, processUid, packageName) == AppOpsManager.MODE_ALLOWED; } finally { Binder.restoreCallingIdentity(token); @@ -669,7 +669,7 @@ public final class MediaProjectionManagerService extends SystemService } @Override // Binder call - public IMediaProjection createProjection(int uid, String packageName, int type, + public IMediaProjection createProjection(int processUid, String packageName, int type, boolean isPermanentGrant) { if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION) != PackageManager.PERMISSION_GRANTED) { @@ -680,13 +680,13 @@ public final class MediaProjectionManagerService extends SystemService throw new IllegalArgumentException("package name must not be empty"); } final UserHandle callingUser = Binder.getCallingUserHandle(); - return createProjectionInternal(uid, packageName, type, isPermanentGrant, + return createProjectionInternal(processUid, packageName, type, isPermanentGrant, callingUser); } @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) - public IMediaProjection getProjection(int uid, String packageName) { + public IMediaProjection getProjection(int processUid, String packageName) { getProjection_enforcePermission(); if (packageName == null || packageName.isEmpty()) { throw new IllegalArgumentException("package name must not be empty"); @@ -695,7 +695,7 @@ public final class MediaProjectionManagerService extends SystemService MediaProjection projection; final long callingToken = Binder.clearCallingIdentity(); try { - projection = getProjectionInternal(uid, packageName); + projection = getProjectionInternal(processUid, packageName); } finally { Binder.restoreCallingIdentity(callingToken); } @@ -869,12 +869,13 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) - public void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) { + public void notifyPermissionRequestInitiated( + int hostProcessUid, int sessionCreationSource) { notifyPermissionRequestInitiated_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { MediaProjectionManagerService.this.notifyPermissionRequestInitiated( - hostUid, sessionCreationSource); + hostProcessUid, sessionCreationSource); } finally { Binder.restoreCallingIdentity(token); } @@ -882,11 +883,11 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) - public void notifyPermissionRequestDisplayed(int hostUid) { + public void notifyPermissionRequestDisplayed(int hostProcessUid) { notifyPermissionRequestDisplayed_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { - MediaProjectionManagerService.this.notifyPermissionRequestDisplayed(hostUid); + MediaProjectionManagerService.this.notifyPermissionRequestDisplayed(hostProcessUid); } finally { Binder.restoreCallingIdentity(token); } @@ -894,11 +895,11 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) - public void notifyPermissionRequestCancelled(int hostUid) { + public void notifyPermissionRequestCancelled(int hostProcessUid) { notifyPermissionRequestCancelled_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { - MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostUid); + MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostProcessUid); } finally { Binder.restoreCallingIdentity(token); } @@ -906,11 +907,11 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) - public void notifyAppSelectorDisplayed(int hostUid) { + public void notifyAppSelectorDisplayed(int hostProcessUid) { notifyAppSelectorDisplayed_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { - MediaProjectionManagerService.this.notifyAppSelectorDisplayed(hostUid); + MediaProjectionManagerService.this.notifyAppSelectorDisplayed(hostProcessUid); } finally { Binder.restoreCallingIdentity(token); } @@ -919,12 +920,12 @@ public final class MediaProjectionManagerService extends SystemService @Override // Binder call @EnforcePermission(MANAGE_MEDIA_PROJECTION) public void notifyWindowingModeChanged( - int contentToRecord, int targetUid, int windowingMode) { + int contentToRecord, int targetProcessUid, int windowingMode) { notifyWindowingModeChanged_enforcePermission(); final long token = Binder.clearCallingIdentity(); try { MediaProjectionManagerService.this.notifyWindowingModeChanged( - contentToRecord, targetUid, windowingMode); + contentToRecord, targetProcessUid, windowingMode); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java index e3880c383632..deb95d8a392d 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java @@ -108,7 +108,7 @@ public class NotificationHistoryManager { for (int i = 0; i < pendingPackageRemovals.size(); i++) { userHistory.onPackageRemoved(pendingPackageRemovals.get(i)); } - mUserPendingPackageRemovals.put(userId, null); + mUserPendingPackageRemovals.remove(userId); } // delete history if it was disabled when the user was locked @@ -133,7 +133,7 @@ public class NotificationHistoryManager { synchronized (mLock) { // Actual data deletion is handled by other parts of the system (the entire directory is // removed) - we just need clean up our internal state for GC - mUserPendingPackageRemovals.put(userId, null); + mUserPendingPackageRemovals.remove(userId); mHistoryEnabled.put(userId, false); mUserPendingHistoryDisables.put(userId, false); onUserStopped(userId); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 7aa7b7e1bfc1..9ddc362769f6 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -215,7 +215,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; @@ -373,6 +372,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.time.Clock; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -2466,8 +2466,8 @@ public class NotificationManagerService extends SystemService { mMetricsLogger = new MetricsLogger(); mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; - mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders, - flagResolver, new ZenModeEventLogger(mPackageManagerClient)); + mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(), + mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient)); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { @Override public void onConfigChanged() { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 911643b1a634..afbf08d9b77d 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -117,6 +117,9 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.PrintWriter; +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -130,9 +133,12 @@ public class ZenModeHelper { static final String TAG = "ZenModeHelper"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + private static final String PACKAGE_ANDROID = "android"; + // The amount of time rules instances can exist without their owning app being installed. private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72; static final int RULE_LIMIT_PER_PACKAGE = 100; + private static final Duration DELETED_RULE_KEPT_FOR = Duration.ofDays(30); private static final String IMPLICIT_RULE_ID_PREFIX = "implicit_"; // + pkg_name @@ -148,6 +154,7 @@ public class ZenModeHelper { private final Context mContext; private final H mHandler; + private final Clock mClock; private final SettingsObserver mSettingsObserver; private final AppOpsManager mAppOps; private final NotificationManager mNotificationManager; @@ -189,11 +196,13 @@ public class ZenModeHelper { private String[] mPriorityOnlyDndExemptPackages; - public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders, + public ZenModeHelper(Context context, Looper looper, Clock clock, + ConditionProviders conditionProviders, SystemUiSystemPropertiesFlags.FlagResolver flagResolver, ZenModeEventLogger zenModeEventLogger) { mContext = context; mHandler = new H(looper); + mClock = clock; addCallback(mMetrics); mAppOps = context.getSystemService(AppOpsManager.class); mNotificationManager = context.getSystemService(NotificationManager.class); @@ -452,6 +461,7 @@ public class ZenModeHelper { newConfig = mConfig.copy(); ZenRule rule = new ZenRule(); populateZenRule(pkg, automaticZenRule, rule, origin, /* isNew= */ true); + rule = maybeRestoreRemovedRule(newConfig, rule, automaticZenRule, origin); newConfig.automaticRules.put(rule.id, rule); maybeReplaceDefaultRule(newConfig, automaticZenRule); @@ -463,6 +473,37 @@ public class ZenModeHelper { } } + private ZenRule maybeRestoreRemovedRule(ZenModeConfig config, ZenRule ruleToAdd, + AutomaticZenRule azrToAdd, @ConfigChangeOrigin int origin) { + if (!Flags.modesApi()) { + return ruleToAdd; + } + String deletedKey = ZenModeConfig.deletedRuleKey(ruleToAdd); + if (deletedKey == null) { + // Couldn't calculate the deletedRuleKey (condition or pkg null?). This should + // never happen for an app-provided rule because NMS validates both. + return ruleToAdd; + } + ZenRule ruleToRestore = config.deletedRules.get(deletedKey); + if (ruleToRestore == null) { + return ruleToAdd; // Cannot restore. + } + + // We have found a previous rule to maybe restore. Whether we do that or not, we don't need + // to keep it around (if not restored now, it won't be in future calls either). + config.deletedRules.remove(deletedKey); + ruleToRestore.deletionInstant = null; + + if (origin != UPDATE_ORIGIN_APP) { + return ruleToAdd; // Okay to create anew. + } + + // "Preserve" the previous rule by considering the azrToAdd an update instead. + // Only app-modifiable fields will actually be modified. + populateZenRule(ruleToRestore.pkg, azrToAdd, ruleToRestore, origin, /* isNew= */ false); + return ruleToRestore; + } + private static void maybeReplaceDefaultRule(ZenModeConfig config, AutomaticZenRule addedRule) { if (!Flags.modesApi()) { return; @@ -644,7 +685,7 @@ public class ZenModeHelper { ZenRule rule = new ZenRule(); rule.id = implicitRuleId(pkg); rule.pkg = pkg; - rule.creationTime = System.currentTimeMillis(); + rule.creationTime = mClock.millis(); Binder.withCleanCallingIdentity(() -> { try { @@ -664,7 +705,7 @@ public class ZenModeHelper { rule.condition = null; rule.conditionId = new Uri.Builder() .scheme(Condition.SCHEME) - .authority("android") + .authority(PACKAGE_ANDROID) .appendPath("implicit") .appendPath(pkg) .build(); @@ -693,7 +734,9 @@ public class ZenModeHelper { if (ruleToRemove == null) return false; if (canManageAutomaticZenRule(ruleToRemove)) { newConfig.automaticRules.remove(id); - if (ruleToRemove.getPkg() != null && !"android".equals(ruleToRemove.getPkg())) { + maybePreserveRemovedRule(newConfig, ruleToRemove, origin); + if (ruleToRemove.getPkg() != null + && !PACKAGE_ANDROID.equals(ruleToRemove.getPkg())) { for (ZenRule currRule : newConfig.automaticRules.values()) { if (currRule.getPkg() != null && currRule.getPkg().equals(ruleToRemove.getPkg())) { @@ -723,12 +766,44 @@ public class ZenModeHelper { ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); if (Objects.equals(rule.getPkg(), packageName) && canManageAutomaticZenRule(rule)) { newConfig.automaticRules.removeAt(i); + maybePreserveRemovedRule(newConfig, rule, origin); + } + } + // If the system is clearing all rules this means DND access is revoked or the package + // was uninstalled, so also clear the preserved-deleted rules. + if (origin == UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI) { + for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) { + ZenRule rule = newConfig.deletedRules.get(newConfig.deletedRules.keyAt(i)); + if (Objects.equals(rule.getPkg(), packageName)) { + newConfig.deletedRules.removeAt(i); + } } } return setConfigLocked(newConfig, origin, reason, null, true, callingUid); } } + private void maybePreserveRemovedRule(ZenModeConfig config, ZenRule ruleToRemove, + @ConfigChangeOrigin int origin) { + if (!Flags.modesApi()) { + return; + } + // If an app deletes a previously customized rule, keep it around to preserve + // the user's customization when/if it's recreated later. + // We don't try to preserve system-owned rules because their conditionIds (used as + // deletedRuleKey) are not stable. This is almost moot anyway because an app cannot + // delete a system-owned rule. + if (origin == UPDATE_ORIGIN_APP && !ruleToRemove.canBeUpdatedByApp() + && !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) { + String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove); + if (deletedKey != null) { + ruleToRemove.deletionInstant = Instant.now(mClock); + // Overwrites a previously-deleted rule with the same conditionId, but that's okay. + config.deletedRules.put(deletedKey, ruleToRemove); + } + } + } + void setAutomaticZenRuleState(String id, Condition condition, @ConfigChangeOrigin int origin, int callingUid) { ZenModeConfig newConfig; @@ -919,7 +994,7 @@ public class ZenModeHelper { // These values can always be edited by the app, so we apply changes immediately. if (isNew) { rule.id = ZenModeConfig.newRuleId(); - rule.creationTime = System.currentTimeMillis(); + rule.creationTime = mClock.millis(); rule.component = automaticZenRule.getOwner(); rule.pkg = pkg; } @@ -1379,7 +1454,7 @@ public class ZenModeHelper { boolean hasDefaultRules = config.automaticRules.containsAll( ZenModeConfig.DEFAULT_RULE_IDS); - long time = System.currentTimeMillis(); + long time = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis(); if (config.automaticRules != null && config.automaticRules.size() > 0) { for (ZenRule automaticRule : config.automaticRules.values()) { if (forRestore) { @@ -1419,6 +1494,12 @@ public class ZenModeHelper { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId); } + + if (Flags.modesApi() && forRestore) { + // Note: forBackup doesn't write deletedRules, but just in case. + config.deletedRules.clear(); + } + if (DEBUG) Log.d(TAG, reason); synchronized (mConfigLock) { setConfigLocked(config, null, @@ -1436,7 +1517,7 @@ public class ZenModeHelper { if (forBackup && mConfigs.keyAt(i) != userId) { continue; } - mConfigs.valueAt(i).writeXml(out, version); + mConfigs.valueAt(i).writeXml(out, version, forBackup); } } } @@ -1468,28 +1549,51 @@ public class ZenModeHelper { } /** - * Removes old rule instances whose owner is not installed. + * Cleans up obsolete rules: + * <ul> + * <li>Rule instances whose owner is not installed. + * <li>Deleted rules that were deleted more than 30 days ago. + * </ul> */ private void cleanUpZenRules() { - long currentTime = System.currentTimeMillis(); + Instant keptRuleThreshold = mClock.instant().minus(DELETED_RULE_KEPT_FOR); synchronized (mConfigLock) { final ZenModeConfig newConfig = mConfig.copy(); - if (newConfig.automaticRules != null) { - for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { - ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); - if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) { - try { - if (rule.getPkg() != null) { - mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER); - } - } catch (PackageManager.NameNotFoundException e) { - newConfig.automaticRules.removeAt(i); + + deleteRulesWithoutOwner(newConfig.automaticRules); + if (Flags.modesApi()) { + deleteRulesWithoutOwner(newConfig.deletedRules); + for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) { + ZenRule deletedRule = newConfig.deletedRules.valueAt(i); + if (deletedRule.deletionInstant == null + || deletedRule.deletionInstant.isBefore(keptRuleThreshold)) { + newConfig.deletedRules.removeAt(i); + } + } + } + + if (!newConfig.equals(mConfig)) { + setConfigLocked(newConfig, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, + "cleanUpZenRules", Process.SYSTEM_UID); + } + } + } + + private void deleteRulesWithoutOwner(ArrayMap<String, ZenRule> ruleList) { + long currentTime = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis(); + if (ruleList != null) { + for (int i = ruleList.size() - 1; i >= 0; i--) { + ZenRule rule = ruleList.valueAt(i); + if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) { + try { + if (rule.getPkg() != null) { + mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER); } + } catch (PackageManager.NameNotFoundException e) { + ruleList.removeAt(i); } } } - setConfigLocked(newConfig, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "cleanUpZenRules", - Process.SYSTEM_UID); } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index dd9541e5dda1..92be4ee3acd9 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -698,7 +698,7 @@ final class InstallPackageHelper { pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId); pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId); // Clear any existing archive state. - pkgSetting.setArchiveState(null, userId); + mPm.mInstallerService.mPackageArchiver.clearArchiveState(packageName, userId); mPm.mSettings.writePackageRestrictionsLPr(userId); mPm.mSettings.writeKernelMappingLPr(pkgSetting); installed = true; @@ -2281,7 +2281,7 @@ final class InstallPackageHelper { installerPackageName); } // Clear any existing archive state. - ps.setArchiveState(null, userId); + mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, userId); } else if (allUsers != null) { // The caller explicitly specified INSTALL_ALL_USERS flag. // Thus, updating the settings to install the app for all users. @@ -2305,7 +2305,8 @@ final class InstallPackageHelper { installerPackageName); } // Clear any existing archive state. - ps.setArchiveState(null, currentUserId); + mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, + currentUserId); } else { ps.setInstalled(false, currentUserId); } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 127bf495d2ac..991555495ad2 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -1610,21 +1610,117 @@ public class LauncherAppsService extends SystemService { "Can't access AppMarketActivity for another user")) { return null; } + final int callingUser = getCallingUserId(); final long identity = Binder.clearCallingIdentity(); + try { - // TODO(b/316118005): Add code to launch the app installer for the packageName. - Intent appMarketIntent = new Intent(Intent.ACTION_MAIN); - appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET); - final PendingIntent pi = PendingIntent.getActivityAsUser( - mContext, /* requestCode */ 0, appMarketIntent, PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT, - /* options */ null, user); - return pi == null ? null : pi.getIntentSender(); + if (packageName == null) { + return buildAppMarketIntentSenderForUser(user); + } + + String installerPackageName = getInstallerPackage(packageName, callingUser); + if (installerPackageName == null + || mPackageManagerInternal.getPackageUid( + installerPackageName, /* flags= */ 0, user.getIdentifier()) + < 0) { + if (DEBUG) { + Log.d( + TAG, + "Can't find installer for " + + packageName + + " in user: " + + user.getIdentifier()); + } + return buildAppMarketIntentSenderForUser(user); + } + + Intent packageInfoIntent = + buildMarketPackageInfoIntent( + packageName, installerPackageName, callingPackage); + if (mPackageManagerInternal + .queryIntentActivities( + packageInfoIntent, + packageInfoIntent.resolveTypeIfNeeded( + mContext.getContentResolver()), + PackageManager.MATCH_ALL, + Process.myUid(), + user.getIdentifier()) + .isEmpty()) { + if (DEBUG) { + Log.d( + TAG, + "Can't resolve package info intent for package " + + packageName + + " and installer: " + + installerPackageName); + } + return buildAppMarketIntentSenderForUser(user); + } + + return buildIntentSenderForUser(packageInfoIntent, user); } finally { Binder.restoreCallingIdentity(identity); } } + @Nullable + private IntentSender buildAppMarketIntentSenderForUser(@NonNull UserHandle user) { + Intent appMarketIntent = new Intent(Intent.ACTION_MAIN); + appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET); + return buildIntentSenderForUser(appMarketIntent, user); + } + + @Nullable + private IntentSender buildIntentSenderForUser( + @NonNull Intent intent, @NonNull UserHandle user) { + final PendingIntent pi = + PendingIntent.getActivityAsUser( + mContext, + /* requestCode */ 0, + intent, + PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE + | PendingIntent.FLAG_CANCEL_CURRENT, + /* options */ null, + user); + return pi == null ? null : pi.getIntentSender(); + } + + @Nullable + private String getInstallerPackage(@NonNull String packageName, int callingUserId) { + String installerPackageName = null; + try { + installerPackageName = + mIPM.getInstallSourceInfo(packageName, callingUserId) + .getInstallingPackageName(); + } catch (RemoteException re) { + Slog.e(TAG, "Couldn't find installer for " + packageName, re); + } + + return installerPackageName; + } + + @NonNull + private Intent buildMarketPackageInfoIntent( + @NonNull String packageName, + @NonNull String installerPackageName, + @NonNull String callingPackage) { + return new Intent(Intent.ACTION_VIEW) + .setData( + new Uri.Builder() + .scheme("market") + .authority("details") + .appendQueryParameter("id", packageName) + .build()) + .putExtra( + Intent.EXTRA_REFERRER, + new Uri.Builder() + .scheme("android-app") + .authority(callingPackage) + .build()) + .setPackage(installerPackageName); + } + @Override public void startActivityAsUser(IApplicationThread caller, String callingPackage, String callingFeatureId, ComponentName component, Rect sourceBounds, diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index a4af5e71000c..3e5759a88213 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -71,6 +71,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Binder; import android.os.Bundle; import android.os.Environment; +import android.os.FileUtils; import android.os.IBinder; import android.os.ParcelableException; import android.os.Process; @@ -309,6 +310,26 @@ public class PackageArchiver { return false; } + void clearArchiveState(String packageName, int userId) { + synchronized (mPm.mLock) { + PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); + if (ps != null) { + ps.setArchiveState(/* archiveState= */ null, userId); + } + } + mPm.mBackgroundHandler.post( + () -> { + File iconsDir = getIconsDir(packageName, userId); + if (!iconsDir.exists()) { + return; + } + // TODO(b/319238030) Move this into installd. + if (!FileUtils.deleteContentsAndDir(iconsDir)) { + Slog.e(TAG, "Failed to clean up archive files for " + packageName); + } + }); + } + @Nullable private String getCurrentLauncherPackageName(int userId) { ComponentName defaultLauncherComponent = mPm.snapshotComputer().getDefaultHomeActivity( @@ -437,8 +458,8 @@ public class PackageArchiver { if (mainActivity.iconBitmap == null) { return null; } - File iconsDir = createIconsDir(userId); - File iconFile = new File(iconsDir, packageName + "-" + index + ".png"); + File iconsDir = createIconsDir(packageName, userId); + File iconFile = new File(iconsDir, index + ".png"); try (FileOutputStream out = new FileOutputStream(iconFile)) { out.write(mainActivity.iconBitmap); out.flush(); @@ -454,14 +475,14 @@ public class PackageArchiver { // The app doesn't define an icon. No need to store anything. return null; } - File iconsDir = createIconsDir(userId); - File iconFile = new File(iconsDir, packageName + "-" + index + ".png"); + File iconsDir = createIconsDir(packageName, userId); + File iconFile = new File(iconsDir, index + ".png"); Bitmap icon = drawableToBitmap(mainActivity.getIcon(/* density= */ 0), iconSize); try (FileOutputStream out = new FileOutputStream(iconFile)) { // Note: Quality is ignored for PNGs. if (!icon.compress(Bitmap.CompressFormat.PNG, /* quality= */ 100, out)) { throw new IOException(TextUtils.formatSimple("Failure to store icon file %s", - iconFile.getName())); + iconFile.getAbsolutePath())); } out.flush(); } @@ -793,8 +814,20 @@ public class PackageArchiver { } @VisibleForTesting - Bitmap decodeIcon(ArchiveActivityInfo archiveActivityInfo) { - return BitmapFactory.decodeFile(archiveActivityInfo.getIconBitmap().toString()); + @Nullable + Bitmap decodeIcon(ArchiveActivityInfo activityInfo) { + Path iconBitmap = activityInfo.getIconBitmap(); + if (iconBitmap == null) { + return null; + } + Bitmap bitmap = BitmapFactory.decodeFile(iconBitmap.toString()); + // TODO(b/278553670) We should throw here after some time. Failing graciously now because + // we've just changed the place where we store icons. + if (bitmap == null) { + Slog.e(TAG, "Archived icon cannot be decoded " + iconBitmap.toAbsolutePath()); + return null; + } + return bitmap; } Bitmap includeCloudOverlay(Bitmap bitmap) { @@ -1075,8 +1108,9 @@ public class PackageArchiver { } } - private static File createIconsDir(@UserIdInt int userId) throws IOException { - File iconsDir = getIconsDir(userId); + private static File createIconsDir(String packageName, @UserIdInt int userId) + throws IOException { + File iconsDir = getIconsDir(packageName, userId); if (!iconsDir.isDirectory()) { iconsDir.delete(); iconsDir.mkdirs(); @@ -1088,8 +1122,10 @@ public class PackageArchiver { return iconsDir; } - private static File getIconsDir(int userId) { - return new File(Environment.getDataSystemCeDirectory(userId), ARCHIVE_ICONS_DIR); + private static File getIconsDir(String packageName, int userId) { + return new File( + new File(Environment.getDataSystemCeDirectory(userId), ARCHIVE_ICONS_DIR), + packageName); } private static byte[] bytesFromBitmapFile(Path path) throws IOException { @@ -1195,7 +1231,7 @@ public class PackageArchiver { UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER, UserHandle.class); if (extraIntent != null && user != null && mAppStateHelper.isAppTopVisible( - getCurrentLauncherPackageName(user.getIdentifier()))) { + getCurrentLauncherPackageName(user.getIdentifier()))) { extraIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivityAsUser(extraIntent, user); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index a9118d46b4ba..fdcd28b0ed02 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -25,6 +25,7 @@ import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVI import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; import static android.content.pm.PackageInstaller.UNARCHIVAL_GENERIC_ERROR; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; +import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; @@ -1405,7 +1406,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, statusReceiver, versionedPackage.getPackageName(), - canSilentlyInstallPackage, userId); + canSilentlyInstallPackage, userId, mPackageArchiver, flags); final boolean shouldShowConfirmationDialog = (flags & PackageManager.DELETE_SHOW_DIALOG) != 0; if (!shouldShowConfirmationDialog @@ -1759,7 +1760,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements binderUid, unarchiveId)); } - session.reportUnarchivalStatus(unarchiveId, status, requiredStorageBytes, + session.reportUnarchivalStatus(status, unarchiveId, requiredStorageBytes, userActionIntent); } } @@ -1828,9 +1829,23 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements private final IntentSender mTarget; private final String mPackageName; private final Notification mNotification; + private final int mUserId; - public PackageDeleteObserverAdapter(Context context, IntentSender target, + @DeleteFlags + private final int mFlags; + + @Nullable + private final PackageArchiver mPackageArchiver; + + PackageDeleteObserverAdapter(Context context, IntentSender target, String packageName, boolean showNotification, int userId) { + this(context, target, packageName, showNotification, userId, + /* packageArchiver= */ null, /* flags= */ 0); + } + + PackageDeleteObserverAdapter(Context context, IntentSender target, + String packageName, boolean showNotification, int userId, + PackageArchiver packageArchiver, @DeleteFlags int flags) { mContext = context; mTarget = target; mPackageName = packageName; @@ -1842,6 +1857,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } else { mNotification = null; } + mUserId = userId; + mPackageArchiver = packageArchiver; + mFlags = flags; } private String getDeviceOwnerDeletedPackageMsg() { @@ -1883,6 +1901,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements SystemMessage.NOTE_PACKAGE_STATE, mNotification); } + if (mPackageArchiver != null + && PackageManager.DELETE_SUCCEEDED != returnCode + && (mFlags & DELETE_ARCHIVE) != 0) { + mPackageArchiver.clearArchiveState(mPackageName, mUserId); + } if (mTarget == null) { return; } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 3adeb4b5925f..446c6293aa35 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -77,6 +77,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.LocaleList; import android.os.Looper; @@ -113,7 +114,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.infra.AndroidFuture; import com.android.internal.logging.MetricsLogger; -import com.android.internal.os.BackgroundThread; import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; @@ -485,7 +485,14 @@ public class ShortcutService extends IShortcutService.Stub { } public ShortcutService(Context context) { - this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false); + this(context, getBgLooper(), /*onyForPackgeManagerApis*/ false); + } + + private static Looper getBgLooper() { + final HandlerThread handlerThread = new HandlerThread("shortcut", + android.os.Process.THREAD_PRIORITY_BACKGROUND); + handlerThread.start(); + return handlerThread.getLooper(); } @VisibleForTesting diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 49af4fedb643..c1b74898e5ae 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -2337,8 +2337,18 @@ public class UserManagerService extends IUserManager.Stub { final long identity = Binder.clearCallingIdentity(); try { final TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class); - if (telecomManager != null && telecomManager.isInCall()) { - flags |= UserManager.SWITCHABILITY_STATUS_USER_IN_CALL; + if (com.android.internal.telephony.flags + .Flags.enforceTelephonyFeatureMappingForPublicApis()) { + if (mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_TELECOM)) { + if (telecomManager != null && telecomManager.isInCall()) { + flags |= UserManager.SWITCHABILITY_STATUS_USER_IN_CALL; + } + } + } else { + if (telecomManager != null && telecomManager.isInCall()) { + flags |= UserManager.SWITCHABILITY_STATUS_USER_IN_CALL; + } } } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 2128c991c273..e2269535d931 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -139,6 +139,7 @@ import com.android.server.power.batterysaver.BatterySaverController; import com.android.server.power.batterysaver.BatterySaverPolicy; import com.android.server.power.batterysaver.BatterySaverStateMachine; import com.android.server.power.batterysaver.BatterySavingStats; +import com.android.server.power.feature.PowerManagerFlags; import dalvik.annotation.optimization.NeverCompile; @@ -329,6 +330,8 @@ public final class PowerManagerService extends SystemService // True if battery saver is supported on this device. private final boolean mBatterySaverSupported; + private final PowerManagerFlags mFeatureFlags; + private boolean mDisableScreenWakeLocksWhileCached; private LightsManager mLightsManager; @@ -1079,6 +1082,10 @@ public final class PowerManagerService extends SystemService DeviceConfigParameterProvider createDeviceConfigParameterProvider() { return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL); } + + PowerManagerFlags getFlags() { + return new PowerManagerFlags(); + } } /** Interface for checking an app op permission */ @@ -1145,6 +1152,7 @@ public final class PowerManagerService extends SystemService mNativeWrapper = injector.createNativeWrapper(); mSystemProperties = injector.createSystemPropertiesWrapper(); mClock = injector.createClock(); + mFeatureFlags = injector.getFlags(); mInjector = injector; mHandlerThread = new ServiceThread(TAG, @@ -4802,6 +4810,7 @@ public final class PowerManagerService extends SystemService mAmbientDisplaySuppressionController.dump(pw); mLowPowerStandbyController.dump(pw); + mFeatureFlags.dump(pw); } private void dumpProto(FileDescriptor fd) { diff --git a/services/core/java/com/android/server/power/feature/Android.bp b/services/core/java/com/android/server/power/feature/Android.bp new file mode 100644 index 000000000000..2295b41009de --- /dev/null +++ b/services/core/java/com/android/server/power/feature/Android.bp @@ -0,0 +1,7 @@ +aconfig_declarations { + name: "power_flags", + package: "com.android.server.power.feature.flags", + srcs: [ + "*.aconfig", + ], +} diff --git a/services/core/java/com/android/server/power/feature/PowerManagerFlags.java b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java new file mode 100644 index 000000000000..a5a7069b6ea1 --- /dev/null +++ b/services/core/java/com/android/server/power/feature/PowerManagerFlags.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 The Android Open 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.power.feature; + +import android.text.TextUtils; +import android.util.Slog; + +import com.android.server.power.feature.flags.Flags; + +import java.io.PrintWriter; +import java.util.function.Supplier; + +/** + * Utility class to read the flags used in the power manager server. + */ +public class PowerManagerFlags { + private static final boolean DEBUG = false; + private static final String TAG = "PowerManagerFlags"; + + private final FlagState mEarlyScreenTimeoutDetectorFlagState = new FlagState( + Flags.FLAG_ENABLE_EARLY_SCREEN_TIMEOUT_DETECTOR, + Flags::enableEarlyScreenTimeoutDetector); + + /** Returns whether early-screen-timeout-detector is enabled on not. */ + public boolean isEarlyScreenTimeoutDetectorEnabled() { + return mEarlyScreenTimeoutDetectorFlagState.isEnabled(); + } + + /** + * dumps all flagstates + * @param pw printWriter + */ + public void dump(PrintWriter pw) { + pw.println("PowerManagerFlags:"); + pw.println(" " + mEarlyScreenTimeoutDetectorFlagState); + } + + private static class FlagState { + + private final String mName; + + private final Supplier<Boolean> mFlagFunction; + private boolean mEnabledSet; + private boolean mEnabled; + + private FlagState(String name, Supplier<Boolean> flagFunction) { + mName = name; + mFlagFunction = flagFunction; + } + + private boolean isEnabled() { + if (mEnabledSet) { + if (DEBUG) { + Slog.d(TAG, mName + ": mEnabled. Recall = " + mEnabled); + } + return mEnabled; + } + mEnabled = mFlagFunction.get(); + if (DEBUG) { + Slog.d(TAG, mName + ": mEnabled. Flag value = " + mEnabled); + } + mEnabledSet = true; + return mEnabled; + } + + @Override + public String toString() { + // remove com.android.server.power.feature.flags. from the beginning of the name. + // align all isEnabled() values. + // Adjust lengths if we end up with longer names + final int nameLength = mName.length(); + return TextUtils.substring(mName, 39, nameLength) + ": " + + TextUtils.formatSimple("%" + (91 - nameLength) + "s%s", " " , isEnabled()) + + " (def:" + mFlagFunction.get() + ")"; + } + } +} diff --git a/services/core/java/com/android/server/power/feature/power_flags.aconfig b/services/core/java/com/android/server/power/feature/power_flags.aconfig new file mode 100644 index 000000000000..c8c16db15e0e --- /dev/null +++ b/services/core/java/com/android/server/power/feature/power_flags.aconfig @@ -0,0 +1,11 @@ +package: "com.android.server.power.feature.flags" + +# Important: Flags must be accessed through PowerManagerFlags. + +flag { + name: "enable_early_screen_timeout_detector" + namespace: "power_manager" + description: "Feature flag for Early Screen Timeout detector" + bug: "309861917" + is_fixed_read_only: true +} diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java index 32656b15b143..c3221e4929bd 100644 --- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java +++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java @@ -170,7 +170,11 @@ public class BatteryUsageStatsProvider { final double minConsumedPowerThreshold = query.getMinConsumedPowerThreshold(); final BatteryUsageStats.Builder batteryUsageStatsBuilder; + long monotonicStartTime, monotonicEndTime; synchronized (stats) { + monotonicStartTime = stats.getMonotonicStartTime(); + monotonicEndTime = stats.getMonotonicEndTime(); + batteryUsageStatsBuilder = new BatteryUsageStats.Builder( stats.getCustomEnergyConsumerNames(), includePowerModels, includeProcessStateData, minConsumedPowerThreshold); @@ -195,35 +199,36 @@ public class BatteryUsageStatsProvider { UidBatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE, getProcessForegroundServiceTimeMs(uid, realtimeUs)); } - } - final int[] powerComponents = query.getPowerComponents(); - final List<PowerCalculator> powerCalculators = getPowerCalculators(); - for (int i = 0, count = powerCalculators.size(); i < count; i++) { - PowerCalculator powerCalculator = powerCalculators.get(i); - if (powerComponents != null) { - boolean include = false; - for (int powerComponent : powerComponents) { - if (powerCalculator.isPowerComponentSupported(powerComponent)) { - include = true; - break; + final int[] powerComponents = query.getPowerComponents(); + final List<PowerCalculator> powerCalculators = getPowerCalculators(); + for (int i = 0, count = powerCalculators.size(); i < count; i++) { + PowerCalculator powerCalculator = powerCalculators.get(i); + if (powerComponents != null) { + boolean include = false; + for (int powerComponent : powerComponents) { + if (powerCalculator.isPowerComponentSupported(powerComponent)) { + include = true; + break; + } + } + if (!include) { + continue; } } - if (!include) { - continue; - } + powerCalculator.calculate(batteryUsageStatsBuilder, stats, realtimeUs, uptimeUs, + query); + } + + if ((query.getFlags() + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) { + batteryUsageStatsBuilder.setBatteryHistory(stats.copyHistory()); } - powerCalculator.calculate(batteryUsageStatsBuilder, stats, realtimeUs, uptimeUs, query); } if (mPowerStatsExporterEnabled) { mPowerStatsExporter.exportAggregatedPowerStats(batteryUsageStatsBuilder, - stats.getMonotonicStartTime(), stats.getMonotonicEndTime()); - } - - if ((query.getFlags() - & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) { - batteryUsageStatsBuilder.setBatteryHistory(stats.copyHistory()); + monotonicStartTime, monotonicEndTime); } BatteryUsageStats batteryUsageStats = batteryUsageStatsBuilder.build(); diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 8d934089524c..13f114138261 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -1279,8 +1279,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba ipw.println(); } - PackageWatchdog.getInstance(mContext).dump(ipw); }); + PackageWatchdog.getInstance(mContext).dump(ipw); } @AnyThread diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 58acbe08acf1..b384725711c4 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -60,6 +60,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.Surface; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; @@ -88,15 +89,25 @@ class TvInputHardwareManager implements TvInputHal.Callback { private final Context mContext; private final Listener mListener; private final TvInputHal mHal = new TvInputHal(this); + + private final Object mLock = new Object(); + + @GuardedBy("mLock") private final SparseArray<Connection> mConnections = new SparseArray<>(); + @GuardedBy("mLock") private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>(); + @GuardedBy("mLock") private final List<HdmiDeviceInfo> mHdmiDeviceList = new ArrayList<>(); /* A map from a device ID to the matching TV input ID. */ + @GuardedBy("mLock") private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>(); /* A map from a HDMI logical address to the matching TV input ID. */ + @GuardedBy("mLock") private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>(); + @GuardedBy("mLock") private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>(); /* A map from a HDMI input parent ID to the related input IDs. */ + @GuardedBy("mLock") private final Map<String, List<String>> mHdmiParentInputMap = new ArrayMap<>(); private final AudioManager mAudioManager; @@ -114,16 +125,16 @@ class TvInputHardwareManager implements TvInputHal.Callback { private int mCurrentIndex = 0; private int mCurrentMaxIndex = 0; + @GuardedBy("mLock") private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); + @GuardedBy("mLock") private final List<Message> mPendingHdmiDeviceEvents = new ArrayList<>(); - + @GuardedBy("mLock") private final List<Message> mPendingTvinputInfoEvents = new ArrayList<>(); // Calls to mListener should happen here. private final Handler mHandler = new ListenerHandler(); - private final Object mLock = new Object(); - public TvInputHardwareManager(Context context, Listener listener) { mContext = context; mListener = listener; @@ -141,7 +152,9 @@ class TvInputHardwareManager implements TvInputHal.Callback { hdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener); hdmiControlService.addSystemAudioModeChangeListener( mHdmiSystemAudioModeChangeListener); - mHdmiDeviceList.addAll(hdmiControlService.getInputDevices()); + synchronized (mLock) { + mHdmiDeviceList.addAll(hdmiControlService.getInputDevices()); + } } catch (RemoteException e) { Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); } @@ -172,6 +185,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @GuardedBy("mLock") private void buildHardwareListLocked() { mHardwareList.clear(); for (int i = 0; i < mConnections.size(); ++i) { @@ -301,6 +315,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @GuardedBy("mLock") private boolean checkUidChangedLocked( Connection connection, int callingUid, int resolvedUserId) { Integer connectionCallingUid = connection.getCallingUidLocked(); @@ -496,6 +511,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @GuardedBy("mLock") private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) { for (TvInputHardwareInfo hardwareInfo : mHardwareList) { if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI @@ -506,6 +522,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { return null; } + @GuardedBy("mLock") private int findDeviceIdForInputIdLocked(String inputId) { for (int i = 0; i < mConnections.size(); ++i) { int key = mConnections.keyAt(i); @@ -597,6 +614,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { return false; } + @GuardedBy("mLock") private void processPendingHdmiDeviceEventsLocked() { for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) { Message msg = it.next(); @@ -611,6 +629,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } + @GuardedBy("mLock") private void processPendingTvInputInfoEventsLocked() { for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) { Message msg = it.next(); @@ -748,6 +767,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { // *Locked methods assume TvInputHardwareManager.mLock is held. + @GuardedBy("mLock") public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback, TvInputInfo info, Integer callingUid, Integer resolvedUserId, ResourceClientProfile profile) { @@ -776,50 +796,62 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @GuardedBy("mLock") public void updateConfigsLocked(TvStreamConfig[] configs) { mConfigs = configs; } + @GuardedBy("mLock") public TvInputHardwareInfo getHardwareInfoLocked() { return mHardwareInfo; } + @GuardedBy("mLock") public TvInputInfo getInfoLocked() { return mInfo; } + @GuardedBy("mLock") public ITvInputHardware getHardwareLocked() { return mHardware; } + @GuardedBy("mLock") public TvInputHardwareImpl getHardwareImplLocked() { return mHardware; } + @GuardedBy("mLock") public ITvInputHardwareCallback getCallbackLocked() { return mCallback; } + @GuardedBy("mLock") public TvStreamConfig[] getConfigsLocked() { return mConfigs; } + @GuardedBy("mLock") public Integer getCallingUidLocked() { return mCallingUid; } + @GuardedBy("mLock") public Integer getResolvedUserIdLocked() { return mResolvedUserId; } + @GuardedBy("mLock") public void setOnFirstFrameCapturedLocked(Runnable runnable) { mOnFirstFrameCaptured = runnable; } + @GuardedBy("mLock") public Runnable getOnFirstFrameCapturedLocked() { return mOnFirstFrameCaptured; } + @GuardedBy("mLock") public ResourceClientProfile getResourceClientProfileLocked() { return mResourceClientProfile; } @@ -844,6 +876,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { + " }"; } + @GuardedBy("mLock") public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) { // Update connection status only if it's not default value if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN @@ -855,10 +888,12 @@ class TvInputHardwareManager implements TvInputHal.Callback { return mIsCableConnectionStatusUpdated; } + @GuardedBy("mLock") private int getConfigsLengthLocked() { return mConfigs == null ? 0 : mConfigs.length; } + @GuardedBy("mLock") private int getInputStateLocked() { int configsLength = getConfigsLengthLocked(); if (configsLength > 0) { @@ -880,7 +915,6 @@ class TvInputHardwareManager implements TvInputHal.Callback { private class TvInputHardwareImpl extends ITvInputHardware.Stub { private final TvInputHardwareInfo mInfo; - private boolean mReleased = false; private final Object mImplLock = new Object(); private final AudioManager.OnAudioPortUpdateListener mAudioListener = @@ -909,28 +943,44 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } }; + @GuardedBy("mImplLock") + private boolean mReleased = false; + @GuardedBy("mImplLock") private int mOverrideAudioType = AudioManager.DEVICE_NONE; + @GuardedBy("mImplLock") private String mOverrideAudioAddress = ""; + @GuardedBy("mImplLock") private AudioDevicePort mAudioSource; + @GuardedBy("mImplLock") private List<AudioDevicePort> mAudioSink = new ArrayList<>(); + @GuardedBy("mImplLock") private AudioPatch mAudioPatch = null; // Set to an invalid value for a volume, so that current volume can be applied at the // first call to updateAudioConfigLocked(). + @GuardedBy("mImplLock") private float mCommittedVolume = -1f; + @GuardedBy("mImplLock") private float mSourceVolume = 0.0f; + @GuardedBy("mImplLock") private TvStreamConfig mActiveConfig = null; + @GuardedBy("mImplLock") private int mDesiredSamplingRate = 0; + @GuardedBy("mImplLock") private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT; + @GuardedBy("mImplLock") private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT; public TvInputHardwareImpl(TvInputHardwareInfo info) { mInfo = info; mAudioManager.registerAudioPortUpdateListener(mAudioListener); if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) { - mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); - findAudioSinkFromAudioPolicy(mAudioSink); + synchronized (mImplLock) { + mAudioSource = + findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress()); + findAudioSinkFromAudioPolicy(mAudioSink); + } } } @@ -1025,6 +1075,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { /** * Update audio configuration (source, sink, patch) all up to current state. */ + @GuardedBy("mImplLock") private void updateAudioConfigLocked() { boolean sinkUpdated = updateAudioSinkLocked(); boolean sourceUpdated = updateAudioSourceLocked(); @@ -1204,6 +1255,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @GuardedBy("mImplLock") private boolean updateAudioSourceLocked() { if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { return false; @@ -1214,6 +1266,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { : !mAudioSource.equals(previousSource); } + @GuardedBy("mImplLock") private boolean updateAudioSinkLocked() { if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) { return false; @@ -1339,16 +1392,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { String inputId = mHardwareInputIdMap.get(deviceId); if (inputId != null) { - if (connection.updateCableConnectionStatusLocked(cableConnectionStatus)) { - if (previousCableConnectionStatus != connection.getInputStateLocked()) { - mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - connection.getInputStateLocked(), 0, inputId).sendToTarget(); - } - } else { - if ((previousConfigsLength == 0) - != (connection.getConfigsLengthLocked() == 0)) { - mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - connection.getInputStateLocked(), 0, inputId).sendToTarget(); + synchronized (mLock) { + if (connection.updateCableConnectionStatusLocked( + cableConnectionStatus)) { + if (previousCableConnectionStatus + != connection.getInputStateLocked()) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + connection.getInputStateLocked(), 0, inputId) + .sendToTarget(); + } + } else { + if ((previousConfigsLength == 0) + != (connection.getConfigsLengthLocked() == 0)) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + connection.getInputStateLocked(), 0, inputId) + .sendToTarget(); + } } } } diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index 9213d96ad4ca..ed04e5fde024 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -34,6 +34,7 @@ public class VcnContext { @NonNull private final Looper mLooper; @NonNull private final VcnNetworkProvider mVcnNetworkProvider; @NonNull private final FeatureFlags mFeatureFlags; + @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; private final boolean mIsInTestMode; public VcnContext( @@ -48,6 +49,7 @@ public class VcnContext { // Auto-generated class mFeatureFlags = new FeatureFlagsImpl(); + mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl(); } @NonNull @@ -69,11 +71,23 @@ public class VcnContext { return mIsInTestMode; } + public boolean isFlagNetworkMetricMonitorEnabled() { + return mFeatureFlags.networkMetricMonitor(); + } + + public boolean isFlagIpSecTransformStateEnabled() { + return mCoreNetFeatureFlags.ipsecTransformState(); + } + @NonNull public FeatureFlags getFeatureFlags() { return mFeatureFlags; } + public boolean isFlagSafeModeTimeoutConfigEnabled() { + return mFeatureFlags.safeModeTimeoutConfig(); + } + /** * Verifies that the caller is running on the VcnContext Thread. * diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 54c97dd37941..3094b182093b 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -915,9 +915,11 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); - logInfo( - "Selected underlying network changed: " - + (underlying == null ? null : underlying.network)); + if (!UnderlyingNetworkRecord.isSameNetwork(mUnderlying, underlying)) { + logInfo( + "Selected underlying network changed: " + + (underlying == null ? null : underlying.network)); + } // TODO(b/179091925): Move the delayed-message handling to BaseState @@ -1242,9 +1244,28 @@ public class VcnGatewayConnection extends StateMachine { createScheduledAlarm( SAFEMODE_TIMEOUT_ALARM, delayedMessage, - mVcnContext.isInTestMode() - ? TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS_TEST_MODE) - : TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + getSafeModeTimeoutMs(mVcnContext, mLastSnapshot, mSubscriptionGroup)); + } + + /** Gets the safe mode timeout */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static long getSafeModeTimeoutMs( + VcnContext vcnContext, TelephonySubscriptionSnapshot snapshot, ParcelUuid subGrp) { + final int defaultSeconds = + vcnContext.isInTestMode() + ? SAFEMODE_TIMEOUT_SECONDS_TEST_MODE + : SAFEMODE_TIMEOUT_SECONDS; + + final PersistableBundleWrapper carrierConfig = snapshot.getCarrierConfigForSubGrp(subGrp); + int resultSeconds = defaultSeconds; + + if (vcnContext.isFlagSafeModeTimeoutConfigEnabled() && carrierConfig != null) { + resultSeconds = + carrierConfig.getInt( + VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY, defaultSeconds); + } + + return TimeUnit.SECONDS.toMillis(resultSeconds); } private void cancelSafeModeAlarm() { @@ -1889,6 +1910,12 @@ public class VcnGatewayConnection extends StateMachine { // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); + if (direction == IpSecManager.DIRECTION_IN + && mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform); + } + // For inbound transforms, additionally allow forwarded traffic to bridge to DUN (as // needed) final Set<Integer> exposedCaps = mConnectionConfig.getAllExposedCapabilities(); diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java new file mode 100644 index 000000000000..5f4852f77727 --- /dev/null +++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.IpSecTransformState; +import android.net.Network; +import android.net.vcn.VcnManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.OutcomeReceiver; +import android.os.PowerManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.VcnContext; + +import java.util.BitSet; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * IpSecPacketLossDetector is responsible for continuously monitoring IPsec packet loss + * + * <p>When the packet loss rate surpass the threshold, IpSecPacketLossDetector will report it to the + * caller + * + * <p>IpSecPacketLossDetector will start monitoring when the network being monitored is selected AND + * an inbound IpSecTransform has been applied to this network. + * + * <p>This class is flag gated by "network_metric_monitor" and "ipsec_tramsform_state" + */ +public class IpSecPacketLossDetector extends NetworkMetricMonitor { + private static final String TAG = IpSecPacketLossDetector.class.getSimpleName(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + static final int PACKET_LOSS_UNAVALAIBLE = -1; + + // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality + // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and + // Security"). For audio and video streaming, above 10-12% packet loss is unacceptable (as per + // "ICTP-SDU: About PingER"). Thus choose 12% as a conservative default threshold to declare a + // validation failure. + private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT = 12; + + private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20; + + private long mPollIpSecStateIntervalMs; + private final int mPacketLossRatePercentThreshold; + + @NonNull private final Handler mHandler; + @NonNull private final PowerManager mPowerManager; + @NonNull private final Object mCancellationToken = new Object(); + @NonNull private final PacketLossCalculator mPacketLossCalculator; + + @Nullable private IpSecTransformWrapper mInboundTransform; + @Nullable private IpSecTransformState mLastIpSecTransformState; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public IpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback, + @NonNull Dependencies deps) + throws IllegalAccessException { + super(vcnContext, network, carrierConfig, callback); + + Objects.requireNonNull(deps, "Missing deps"); + + if (!vcnContext.isFlagIpSecTransformStateEnabled()) { + // Caller error + logWtf("ipsecTransformState flag disabled"); + throw new IllegalAccessException("ipsecTransformState flag disabled"); + } + + mHandler = new Handler(getVcnContext().getLooper()); + + mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class); + + mPacketLossCalculator = deps.getPacketLossCalculator(); + + mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig); + + // Register for system broadcasts to monitor idle mode change + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + getVcnContext() + .getContext() + .registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals( + intent.getAction()) + && mPowerManager.isDeviceIdleMode()) { + mLastIpSecTransformState = null; + } + } + }, + intentFilter, + null /* broadcastPermission not required */, + mHandler); + } + + public IpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + this(vcnContext, network, carrierConfig, callback, new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + public PacketLossCalculator getPacketLossCalculator() { + return new PacketLossCalculator(); + } + } + + private static long getPollIpSecStateIntervalMs( + @Nullable PersistableBundleWrapper carrierConfig) { + final int seconds; + + if (carrierConfig != null) { + seconds = + carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY, + POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT); + } else { + seconds = POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT; + } + + return TimeUnit.SECONDS.toMillis(seconds); + } + + private static int getPacketLossRatePercentThreshold( + @Nullable PersistableBundleWrapper carrierConfig) { + if (carrierConfig != null) { + return carrierConfig.getInt( + VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY, + IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT); + } + return IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT; + } + + @Override + protected void onSelectedUnderlyingNetworkChanged() { + if (!isSelectedUnderlyingNetwork()) { + mInboundTransform = null; + stop(); + } + + // No action when the underlying network got selected. Wait for the inbound transform to + // start the monitor + } + + @Override + public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inboundTransform) { + Objects.requireNonNull(inboundTransform, "inboundTransform is null"); + + if (Objects.equals(inboundTransform, mInboundTransform)) { + return; + } + + if (!isSelectedUnderlyingNetwork()) { + logWtf("setInboundTransform called but network not selected"); + return; + } + + // When multiple parallel inbound transforms are created, NetworkMetricMonitor will be + // enabled on the last one as a sample + mInboundTransform = inboundTransform; + start(); + } + + @Override + public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) { + // The already scheduled event will not be affected. The followup events will be scheduled + // with the new interval + mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig); + } + + @Override + protected void start() { + super.start(); + clearTransformStateAndPollingEvents(); + mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L); + } + + @Override + public void stop() { + super.stop(); + clearTransformStateAndPollingEvents(); + } + + private void clearTransformStateAndPollingEvents() { + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + mLastIpSecTransformState = null; + } + + @Override + public void close() { + super.close(); + + if (mInboundTransform != null) { + mInboundTransform.close(); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @Nullable + public IpSecTransformState getLastTransformState() { + return mLastIpSecTransformState; + } + + @VisibleForTesting(visibility = Visibility.PROTECTED) + @Nullable + public IpSecTransformWrapper getInboundTransformInternal() { + return mInboundTransform; + } + + private class PollIpSecStateRunnable implements Runnable { + @Override + public void run() { + if (!isStarted()) { + logWtf("Monitor stopped but PollIpSecStateRunnable not removed from Handler"); + return; + } + + getInboundTransformInternal() + .getIpSecTransformState( + new HandlerExecutor(mHandler), new IpSecTransformStateReceiver()); + + // Schedule for next poll + mHandler.postDelayed( + new PollIpSecStateRunnable(), mCancellationToken, mPollIpSecStateIntervalMs); + } + } + + private class IpSecTransformStateReceiver + implements OutcomeReceiver<IpSecTransformState, RuntimeException> { + @Override + public void onResult(@NonNull IpSecTransformState state) { + getVcnContext().ensureRunningOnLooperThread(); + + if (!isStarted()) { + return; + } + + onIpSecTransformStateReceived(state); + } + + @Override + public void onError(@NonNull RuntimeException error) { + getVcnContext().ensureRunningOnLooperThread(); + + // Nothing we can do here + logW("TransformStateReceiver#onError " + error.toString()); + } + } + + private void onIpSecTransformStateReceived(@NonNull IpSecTransformState state) { + if (mLastIpSecTransformState == null) { + // This is first time to poll the state + mLastIpSecTransformState = state; + return; + } + + final int packetLossRate = + mPacketLossCalculator.getPacketLossRatePercentage( + mLastIpSecTransformState, state, getLogPrefix()); + + if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) { + return; + } + + final String logMsg = + "packetLossRate: " + + packetLossRate + + "% in the past " + + (state.getTimestamp() - mLastIpSecTransformState.getTimestamp()) + + "ms"; + + mLastIpSecTransformState = state; + if (packetLossRate < mPacketLossRatePercentThreshold) { + logV(logMsg); + onValidationResultReceivedInternal(false /* isFailed */); + } else { + logInfo(logMsg); + onValidationResultReceivedInternal(true /* isFailed */); + } + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class PacketLossCalculator { + /** Calculate the packet loss rate between two timestamps */ + public int getPacketLossRatePercentage( + @NonNull IpSecTransformState oldState, + @NonNull IpSecTransformState newState, + String logPrefix) { + logVIpSecTransform("oldState", oldState, logPrefix); + logVIpSecTransform("newState", newState, logPrefix); + + final int replayWindowSize = oldState.getReplayBitmap().length * 8; + final long oldSeqHi = oldState.getRxHighestSequenceNumber(); + final long oldSeqLow = Math.max(0L, oldSeqHi - replayWindowSize + 1); + final long newSeqHi = newState.getRxHighestSequenceNumber(); + final long newSeqLow = Math.max(0L, newSeqHi - replayWindowSize + 1); + + if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) { + // The replay window did not proceed and all packets might have been delivered out + // of order + return PACKET_LOSS_UNAVALAIBLE; + } + + // Get the expected packet count by assuming there is no packet loss. In this case, SA + // should receive all packets whose sequence numbers are smaller than the lower bound of + // the replay window AND the packets received within the window. + // When the lower bound is 0, it's not possible to tell whether packet with seqNo 0 is + // received or not. For simplicity just assume that packet is received. + final long newExpectedPktCnt = newSeqLow + getPacketCntInReplayWindow(newState); + final long oldExpectedPktCnt = oldSeqLow + getPacketCntInReplayWindow(oldState); + + final long expectedPktCntDiff = newExpectedPktCnt - oldExpectedPktCnt; + final long actualPktCntDiff = newState.getPacketCount() - oldState.getPacketCount(); + + logV( + TAG, + logPrefix + + " expectedPktCntDiff: " + + expectedPktCntDiff + + " actualPktCntDiff: " + + actualPktCntDiff); + + if (expectedPktCntDiff < 0 + || expectedPktCntDiff == 0 + || actualPktCntDiff < 0 + || actualPktCntDiff > expectedPktCntDiff) { + logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff"); + return PACKET_LOSS_UNAVALAIBLE; + } + + return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff); + } + } + + private static void logVIpSecTransform( + String transformTag, IpSecTransformState state, String logPrefix) { + final String stateString = + " seqNo: " + + state.getRxHighestSequenceNumber() + + " | pktCnt: " + + state.getPacketCount() + + " | pktCntInWindow: " + + getPacketCntInReplayWindow(state); + logV(TAG, logPrefix + " " + transformTag + stateString); + } + + /** Get the number of received packets within the replay window */ + private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) { + return BitSet.valueOf(state.getReplayBitmap()).cardinality(); + } +} diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java new file mode 100644 index 000000000000..a79f188713e1 --- /dev/null +++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static com.android.server.VcnManagementService.LOCAL_LOG; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.IpSecTransform; +import android.net.IpSecTransformState; +import android.net.Network; +import android.os.OutcomeReceiver; +import android.util.CloseGuard; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.server.vcn.VcnContext; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * NetworkMetricMonitor is responsible for managing metric monitoring and tracking validation + * results. + * + * <p>This class is flag gated by "network_metric_monitor" + */ +public abstract class NetworkMetricMonitor implements AutoCloseable { + private static final String TAG = NetworkMetricMonitor.class.getSimpleName(); + + private static final boolean VDBG = false; // STOPSHIP: if true + + @NonNull private final CloseGuard mCloseGuard = new CloseGuard(); + + @NonNull private final VcnContext mVcnContext; + @NonNull private final Network mNetwork; + @NonNull private final NetworkMetricMonitorCallback mCallback; + + private boolean mIsSelectedUnderlyingNetwork; + private boolean mIsStarted; + private boolean mIsValidationFailed; + + protected NetworkMetricMonitor( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) { + // Caller error + logWtf("networkMetricMonitor flag disabled"); + throw new IllegalAccessException("networkMetricMonitor flag disabled"); + } + + mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + mNetwork = Objects.requireNonNull(network, "Missing network"); + mCallback = Objects.requireNonNull(callback, "Missing callback"); + + mIsSelectedUnderlyingNetwork = false; + mIsStarted = false; + mIsValidationFailed = false; + } + + /** Callback to notify caller of the validation result */ + public interface NetworkMetricMonitorCallback { + /** Called when there is a validation result is ready */ + void onValidationResultReceived(); + } + + /** + * Start monitoring + * + * <p>This method might be called on a an already started monitor for updating monitor + * properties (e.g. IpSecTransform, carrier config) + * + * <p>Subclasses MUST call super.start() when overriding this method + */ + protected void start() { + mIsStarted = true; + } + + /** + * Stop monitoring + * + * <p>Subclasses MUST call super.stop() when overriding this method + */ + public void stop() { + mIsValidationFailed = false; + mIsStarted = false; + } + + /** Called by the subclasses when the validation result is ready */ + protected void onValidationResultReceivedInternal(boolean isFailed) { + mIsValidationFailed = isFailed; + mCallback.onValidationResultReceived(); + } + + /** Called when the underlying network changes to selected or unselected */ + protected abstract void onSelectedUnderlyingNetworkChanged(); + + /** + * Mark the network being monitored selected or unselected + * + * <p>Subclasses MUST call super when overriding this method + */ + public void setIsSelectedUnderlyingNetwork(boolean isSelectedUnderlyingNetwork) { + if (mIsSelectedUnderlyingNetwork == isSelectedUnderlyingNetwork) { + return; + } + + mIsSelectedUnderlyingNetwork = isSelectedUnderlyingNetwork; + onSelectedUnderlyingNetworkChanged(); + } + + /** Wrapper that allows injection for testing purposes */ + @VisibleForTesting(visibility = Visibility.PROTECTED) + public static class IpSecTransformWrapper { + @NonNull public final IpSecTransform ipSecTransform; + + public IpSecTransformWrapper(@NonNull IpSecTransform ipSecTransform) { + this.ipSecTransform = ipSecTransform; + } + + /** Poll an IpSecTransformState */ + public void getIpSecTransformState( + @NonNull Executor executor, + @NonNull OutcomeReceiver<IpSecTransformState, RuntimeException> callback) { + ipSecTransform.getIpSecTransformState(executor, callback); + } + + /** Close this instance and release the underlying resources */ + public void close() { + ipSecTransform.close(); + } + + @Override + public int hashCode() { + return Objects.hash(ipSecTransform); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof IpSecTransformWrapper)) { + return false; + } + + final IpSecTransformWrapper other = (IpSecTransformWrapper) o; + + return Objects.equals(ipSecTransform, other.ipSecTransform); + } + } + + /** Set the IpSecTransform that applied to the Network being monitored */ + public void setInboundTransform(@NonNull IpSecTransform inTransform) { + setInboundTransformInternal(new IpSecTransformWrapper(inTransform)); + } + + /** + * Set the IpSecTransform that applied to the Network being monitored * + * + * <p>Subclasses MUST call super when overriding this method + */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inTransform) { + // Subclasses MUST override it if they care + } + + /** Update the carrierconfig */ + public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) { + // Subclasses MUST override it if they care + } + + public boolean isValidationFailed() { + return mIsValidationFailed; + } + + public boolean isSelectedUnderlyingNetwork() { + return mIsSelectedUnderlyingNetwork; + } + + public boolean isStarted() { + return mIsStarted; + } + + @NonNull + public VcnContext getVcnContext() { + return mVcnContext; + } + + // Override methods for AutoCloseable. Subclasses MUST call super when overriding this method + @Override + public void close() { + mCloseGuard.close(); + + stop(); + } + + // Override #finalize() to use closeGuard for flagging that #close() was not called + @SuppressWarnings("Finalize") + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } finally { + super.finalize(); + } + } + + private String getClassName() { + return this.getClass().getSimpleName(); + } + + protected String getLogPrefix() { + return " [Network " + mNetwork + "] "; + } + + protected void logV(String msg) { + if (VDBG) { + Slog.v(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[VERBOSE ] " + getClassName() + getLogPrefix() + msg); + } + } + + protected void logInfo(String msg) { + Slog.i(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[INFO ] " + getClassName() + getLogPrefix() + msg); + } + + protected void logW(String msg) { + Slog.w(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[WARN ] " + getClassName() + getLogPrefix() + msg); + } + + protected void logWtf(String msg) { + Slog.wtf(getClassName(), getLogPrefix() + msg); + LOCAL_LOG.log("[WTF ] " + getClassName() + getLogPrefix() + msg); + } + + protected static void logV(String className, String msgWithPrefix) { + if (VDBG) { + Slog.wtf(className, msgWithPrefix); + LOCAL_LOG.log("[VERBOSE ] " + className + msgWithPrefix); + } + } + + protected static void logWtf(String className, String msgWithPrefix) { + Slog.wtf(className, msgWithPrefix); + LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix); + } +} diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java index 7f129ea3801c..d32e5cc8ef80 100644 --- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java +++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java @@ -47,7 +47,6 @@ import com.android.server.vcn.VcnContext; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; /** @hide */ @@ -86,7 +85,6 @@ class NetworkPriorityClassifier { * <p>VCN MUST never select a non-INTERNET network that are unvalidated or fail to match any * template as the underlying network. */ - @VisibleForTesting(visibility = Visibility.PRIVATE) static final int PRIORITY_INVALID = -1; /** Gives networks a priority class, based on configured VcnGatewayConnectionConfig */ @@ -96,7 +94,7 @@ class NetworkPriorityClassifier { List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { // mRouteSelectionNetworkRequest requires a network be both VALIDATED and NOT_SUSPENDED @@ -118,7 +116,7 @@ class NetworkPriorityClassifier { networkRecord, subscriptionGroup, snapshot, - currentlySelected, + isSelected, carrierConfig)) { return priorityIndex; } @@ -140,12 +138,9 @@ class NetworkPriorityClassifier { UnderlyingNetworkRecord networkRecord, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; - final boolean isSelectedUnderlyingNetwork = - currentlySelected != null - && Objects.equals(currentlySelected.network, networkRecord.network); final int meteredMatch = networkPriority.getMetered(); final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED); @@ -159,7 +154,7 @@ class NetworkPriorityClassifier { if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps() || (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinEntryUpstreamBandwidthKbps() - && !isSelectedUnderlyingNetwork)) { + && !isSelected)) { return false; } @@ -167,7 +162,7 @@ class NetworkPriorityClassifier { < networkPriority.getMinExitDownstreamBandwidthKbps() || (caps.getLinkDownstreamBandwidthKbps() < networkPriority.getMinEntryDownstreamBandwidthKbps() - && !isSelectedUnderlyingNetwork)) { + && !isSelected)) { return false; } @@ -191,7 +186,7 @@ class NetworkPriorityClassifier { return checkMatchesWifiPriorityRule( (VcnWifiUnderlyingNetworkTemplate) networkPriority, networkRecord, - currentlySelected, + isSelected, carrierConfig); } @@ -214,7 +209,7 @@ class NetworkPriorityClassifier { public static boolean checkMatchesWifiPriorityRule( VcnWifiUnderlyingNetworkTemplate networkPriority, UnderlyingNetworkRecord networkRecord, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; @@ -223,7 +218,7 @@ class NetworkPriorityClassifier { } // TODO: Move the Network Quality check to the network metric monitor framework. - if (!isWifiRssiAcceptable(networkRecord, currentlySelected, carrierConfig)) { + if (!isWifiRssiAcceptable(networkRecord, isSelected, carrierConfig)) { return false; } @@ -237,15 +232,11 @@ class NetworkPriorityClassifier { private static boolean isWifiRssiAcceptable( UnderlyingNetworkRecord networkRecord, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, PersistableBundleWrapper carrierConfig) { final NetworkCapabilities caps = networkRecord.networkCapabilities; - final boolean isSelectedNetwork = - currentlySelected != null - && networkRecord.network.equals(currentlySelected.network); - if (isSelectedNetwork - && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { + if (isSelected && caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) { return true; } diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 6afa795e96fa..3f8d39e72e89 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -30,6 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -48,9 +49,11 @@ import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; @@ -83,6 +86,9 @@ public class UnderlyingNetworkController { @NonNull private final TelephonyCallback mActiveDataSubIdListener = new VcnActiveDataSubscriptionIdListener(); + private final Map<Network, UnderlyingNetworkEvaluator> mUnderlyingNetworkRecords = + new ArrayMap<>(); + @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>(); @Nullable private NetworkCallback mWifiBringupCallback; @Nullable private NetworkCallback mWifiEntryRssiThresholdCallback; @@ -105,7 +111,8 @@ public class UnderlyingNetworkController { this(vcnContext, connectionConfig, subscriptionGroup, snapshot, cb, new Dependencies()); } - private UnderlyingNetworkController( + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkController( @NonNull VcnContext vcnContext, @NonNull VcnGatewayConnectionConfig connectionConfig, @NonNull ParcelUuid subscriptionGroup, @@ -197,6 +204,15 @@ public class UnderlyingNetworkController { List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.close(); + } + } + + mUnderlyingNetworkRecords.clear(); + // Register new callbacks. Make-before-break; always register new callbacks before removal // of old callbacks if (!mIsQuitting) { @@ -395,15 +411,58 @@ public class UnderlyingNetworkController { // Update carrier config mCarrierConfig = mLastSnapshot.getCarrierConfigForSubGrp(mSubscriptionGroup); + // Make sure all evaluators use the same updated TelephonySubscriptionSnapshot and carrier + // config to calculate their cached priority classes. For simplicity, the + // UnderlyingNetworkController does not listen for changes in VCN-related carrier config + // keys, and changes are applied at restart of the VcnGatewayConnection + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.reevaluate( + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + } + // Only trigger re-registration if subIds in this group have changed if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { + + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + reevaluateNetworks(); + } return; } registerOrUpdateNetworkRequests(); } + /** + * Pass the IpSecTransform of the VCN to UnderlyingNetworkController for metric monitoring + * + * <p>Caller MUST call it when IpSecTransforms have been created for VCN creation or migration + */ + public void updateInboundTransform( + @NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) { + if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() + || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + logWtf("#updateInboundTransform: unexpected call; flags missing"); + return; + } + + Objects.requireNonNull(currentNetwork, "currentNetwork is null"); + Objects.requireNonNull(transform, "transform is null"); + + if (mCurrentRecord == null + || mRouteSelectionCallback == null + || !Objects.equals(currentNetwork.network, mCurrentRecord.network)) { + // The caller (VcnGatewayConnection) is out-of-dated. Ignore this call. + return; + } + + mUnderlyingNetworkRecords.get(mCurrentRecord.network).setInboundTransform(transform); + } + /** Tears down this Tracker, and releases all underlying network requests. */ public void teardown() { mVcnContext.ensureRunningOnLooperThread(); @@ -418,32 +477,62 @@ public class UnderlyingNetworkController { .unregisterTelephonyCallback(mActiveDataSubIdListener); } + private TreeSet<UnderlyingNetworkEvaluator> getSortedUnderlyingNetworks() { + TreeSet<UnderlyingNetworkEvaluator> sorted = + new TreeSet<>(UnderlyingNetworkEvaluator.getComparator(mVcnContext)); + + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + if (evaluator.getPriorityClass() != NetworkPriorityClassifier.PRIORITY_INVALID) { + sorted.add(evaluator); + } + } + + return sorted; + } + private void reevaluateNetworks() { if (mIsQuitting || mRouteSelectionCallback == null) { return; // UnderlyingNetworkController has quit. } - TreeSet<UnderlyingNetworkRecord> sorted = - mRouteSelectionCallback.getSortedUnderlyingNetworks(); - UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first(); + TreeSet<UnderlyingNetworkEvaluator> sorted = getSortedUnderlyingNetworks(); + + UnderlyingNetworkEvaluator candidateEvaluator = sorted.isEmpty() ? null : sorted.first(); + UnderlyingNetworkRecord candidate = + candidateEvaluator == null ? null : candidateEvaluator.getNetworkRecord(); if (Objects.equals(mCurrentRecord, candidate)) { return; } String allNetworkPriorities = ""; - for (UnderlyingNetworkRecord record : sorted) { + for (UnderlyingNetworkEvaluator recordEvaluator : sorted) { if (!allNetworkPriorities.isEmpty()) { allNetworkPriorities += ", "; } - allNetworkPriorities += record.network + ": " + record.priorityClass; + allNetworkPriorities += + recordEvaluator.getNetwork() + ": " + recordEvaluator.getPriorityClass(); } - logInfo( - "Selected network changed to " - + (candidate == null ? null : candidate.network) - + ", selected from list: " - + allNetworkPriorities); + + if (!UnderlyingNetworkRecord.isSameNetwork(mCurrentRecord, candidate)) { + logInfo( + "Selected network changed to " + + (candidate == null ? null : candidate.network) + + ", selected from list: " + + allNetworkPriorities); + } + mCurrentRecord = candidate; mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); + + // Need to update all evaluators to ensure the previously selected one is unselected + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.setIsSelected( + candidateEvaluator == evaluator, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + } } /** @@ -463,46 +552,32 @@ public class UnderlyingNetworkController { */ @VisibleForTesting class UnderlyingNetworkListener extends NetworkCallback { - private final Map<Network, UnderlyingNetworkRecord.Builder> - mUnderlyingNetworkRecordBuilders = new ArrayMap<>(); - UnderlyingNetworkListener() { super(NetworkCallback.FLAG_INCLUDE_LOCATION_INFO); } - private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() { - TreeSet<UnderlyingNetworkRecord> sorted = - new TreeSet<>(UnderlyingNetworkRecord.getComparator()); - - for (UnderlyingNetworkRecord.Builder builder : - mUnderlyingNetworkRecordBuilders.values()) { - if (builder.isValid()) { - final UnderlyingNetworkRecord record = - builder.build( - mVcnContext, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), - mSubscriptionGroup, - mLastSnapshot, - mCurrentRecord, - mCarrierConfig); - if (record.priorityClass != NetworkPriorityClassifier.PRIORITY_INVALID) { - sorted.add(record); - } - } - } - - return sorted; - } - @Override public void onAvailable(@NonNull Network network) { - mUnderlyingNetworkRecordBuilders.put( - network, new UnderlyingNetworkRecord.Builder(network)); + mUnderlyingNetworkRecords.put( + network, + mDeps.newUnderlyingNetworkEvaluator( + mVcnContext, + network, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig, + new NetworkEvaluatorCallbackImpl())); } @Override public void onLost(@NonNull Network network) { - mUnderlyingNetworkRecordBuilders.remove(network); + if (mVcnContext.isFlagNetworkMetricMonitorEnabled() + && mVcnContext.isFlagIpSecTransformStateEnabled()) { + mUnderlyingNetworkRecords.get(network).close(); + } + + mUnderlyingNetworkRecords.remove(network); reevaluateNetworks(); } @@ -510,15 +585,20 @@ public class UnderlyingNetworkController { @Override public void onCapabilitiesChanged( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got capabilities change for unknown key: " + network); return; } - builder.setNetworkCapabilities(networkCapabilities); - if (builder.isValid()) { + evaluator.setNetworkCapabilities( + networkCapabilities, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } @@ -526,35 +606,60 @@ public class UnderlyingNetworkController { @Override public void onLinkPropertiesChanged( @NonNull Network network, @NonNull LinkProperties linkProperties) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got link properties change for unknown key: " + network); return; } - builder.setLinkProperties(linkProperties); - if (builder.isValid()) { + evaluator.setLinkProperties( + linkProperties, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } @Override public void onBlockedStatusChanged(@NonNull Network network, boolean isBlocked) { - final UnderlyingNetworkRecord.Builder builder = - mUnderlyingNetworkRecordBuilders.get(network); - if (builder == null) { + final UnderlyingNetworkEvaluator evaluator = mUnderlyingNetworkRecords.get(network); + if (evaluator == null) { logWtf("Got blocked status change for unknown key: " + network); return; } - builder.setIsBlocked(isBlocked); - if (builder.isValid()) { + evaluator.setIsBlocked( + isBlocked, + mConnectionConfig.getVcnUnderlyingNetworkPriorities(), + mSubscriptionGroup, + mLastSnapshot, + mCarrierConfig); + + if (evaluator.isValid()) { reevaluateNetworks(); } } } + @VisibleForTesting + class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback { + @Override + public void onEvaluationResultChanged() { + if (!mVcnContext.isFlagNetworkMetricMonitorEnabled() + || !mVcnContext.isFlagIpSecTransformStateEnabled()) { + logWtf("#onEvaluationResultChanged: unexpected call; flags missing"); + return; + } + + mVcnContext.ensureRunningOnLooperThread(); + reevaluateNetworks(); + } + } + private String getLogPrefix() { return "(" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) @@ -614,16 +719,8 @@ public class UnderlyingNetworkController { pw.println("Underlying networks:"); pw.increaseIndent(); if (mRouteSelectionCallback != null) { - for (UnderlyingNetworkRecord record : - mRouteSelectionCallback.getSortedUnderlyingNetworks()) { - record.dump( - mVcnContext, - pw, - mConnectionConfig.getVcnUnderlyingNetworkPriorities(), - mSubscriptionGroup, - mLastSnapshot, - mCurrentRecord, - mCarrierConfig); + for (UnderlyingNetworkEvaluator recordEvaluator : getSortedUnderlyingNetworks()) { + recordEvaluator.dump(pw); } } pw.decreaseIndent(); @@ -653,5 +750,24 @@ public class UnderlyingNetworkController { @Nullable UnderlyingNetworkRecord underlyingNetworkRecord); } - private static class Dependencies {} + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + public UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback) { + return new UnderlyingNetworkEvaluator( + vcnContext, + network, + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + carrierConfig, + evaluatorCallback); + } + } } diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java new file mode 100644 index 000000000000..2f4cf5e5d8c7 --- /dev/null +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static com.android.server.VcnManagementService.LOCAL_LOG; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.IpSecTransform; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnManager; +import android.net.vcn.VcnUnderlyingNetworkTemplate; +import android.os.Handler; +import android.os.ParcelUuid; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * UnderlyingNetworkEvaluator evaluates the quality and priority class of a network candidate for + * route selection. + * + * @hide + */ +public class UnderlyingNetworkEvaluator { + private static final String TAG = UnderlyingNetworkEvaluator.class.getSimpleName(); + + private static final int[] PENALTY_TIMEOUT_MINUTES_DEFAULT = new int[] {5}; + + @NonNull private final VcnContext mVcnContext; + @NonNull private final Handler mHandler; + @NonNull private final Object mCancellationToken = new Object(); + + @NonNull private final UnderlyingNetworkRecord.Builder mNetworkRecordBuilder; + + @NonNull private final NetworkEvaluatorCallback mEvaluatorCallback; + @NonNull private final List<NetworkMetricMonitor> mMetricMonitors = new ArrayList<>(); + + @NonNull private final Dependencies mDependencies; + + // TODO: Support back-off timeouts + private long mPenalizedTimeoutMs; + + private boolean mIsSelected; + private boolean mIsPenalized; + private int mPriorityClass = NetworkPriorityClassifier.PRIORITY_INVALID; + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public UnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback, + @NonNull Dependencies dependencies) { + mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext"); + mHandler = new Handler(mVcnContext.getLooper()); + + mDependencies = Objects.requireNonNull(dependencies, "Missing dependencies"); + mEvaluatorCallback = Objects.requireNonNull(evaluatorCallback, "Missing deps"); + + Objects.requireNonNull(underlyingNetworkTemplates, "Missing underlyingNetworkTemplates"); + Objects.requireNonNull(subscriptionGroup, "Missing subscriptionGroup"); + Objects.requireNonNull(lastSnapshot, "Missing lastSnapshot"); + + mNetworkRecordBuilder = + new UnderlyingNetworkRecord.Builder( + Objects.requireNonNull(network, "Missing network")); + mIsSelected = false; + mIsPenalized = false; + mPenalizedTimeoutMs = getPenaltyTimeoutMs(carrierConfig); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + if (isIpSecPacketLossDetectorEnabled()) { + try { + mMetricMonitors.add( + mDependencies.newIpSecPacketLossDetector( + mVcnContext, + mNetworkRecordBuilder.getNetwork(), + carrierConfig, + new MetricMonitorCallbackImpl())); + } catch (IllegalAccessException e) { + // No action. Do not add anything to mMetricMonitors + } + } + } + + public UnderlyingNetworkEvaluator( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkEvaluatorCallback evaluatorCallback) { + this( + vcnContext, + network, + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + carrierConfig, + evaluatorCallback, + new Dependencies()); + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + public static class Dependencies { + /** Get an IpSecPacketLossDetector instance */ + public IpSecPacketLossDetector newIpSecPacketLossDetector( + @NonNull VcnContext vcnContext, + @NonNull Network network, + @Nullable PersistableBundleWrapper carrierConfig, + @NonNull NetworkMetricMonitor.NetworkMetricMonitorCallback callback) + throws IllegalAccessException { + return new IpSecPacketLossDetector(vcnContext, network, carrierConfig, callback); + } + } + + /** Callback to notify caller to reevaluate network selection */ + public interface NetworkEvaluatorCallback { + /** + * Called when mIsPenalized changed + * + * <p>When receiving this call, UnderlyingNetworkController should reevaluate all network + * candidates for VCN underlying network selection + */ + void onEvaluationResultChanged(); + } + + private class MetricMonitorCallbackImpl + implements NetworkMetricMonitor.NetworkMetricMonitorCallback { + public void onValidationResultReceived() { + mVcnContext.ensureRunningOnLooperThread(); + + handleValidationResult(); + } + } + + private void updatePriorityClass( + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + if (mNetworkRecordBuilder.isValid()) { + mPriorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + mNetworkRecordBuilder.build(), + underlyingNetworkTemplates, + subscriptionGroup, + lastSnapshot, + mIsSelected, + carrierConfig); + } else { + mPriorityClass = NetworkPriorityClassifier.PRIORITY_INVALID; + } + } + + private boolean isIpSecPacketLossDetectorEnabled() { + return isIpSecPacketLossDetectorEnabled(mVcnContext); + } + + private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) { + return vcnContext.isFlagIpSecTransformStateEnabled() + && vcnContext.isFlagNetworkMetricMonitorEnabled(); + } + + /** Get the comparator for UnderlyingNetworkEvaluator */ + public static Comparator<UnderlyingNetworkEvaluator> getComparator(VcnContext vcnContext) { + return (left, right) -> { + if (isIpSecPacketLossDetectorEnabled(vcnContext)) { + if (left.mIsPenalized != right.mIsPenalized) { + // A penalized network should have lower priority which means a larger index + return left.mIsPenalized ? 1 : -1; + } + } + + final int leftIndex = left.mPriorityClass; + final int rightIndex = right.mPriorityClass; + + // In the case of networks in the same priority class, prioritize based on other + // criteria (eg. actively selected network, link metrics, etc) + if (leftIndex == rightIndex) { + // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord + // fall into the same priority class. + if (left.mIsSelected) { + return -1; + } + if (right.mIsSelected) { + return 1; + } + } + return Integer.compare(leftIndex, rightIndex); + }; + } + + private static long getPenaltyTimeoutMs(@Nullable PersistableBundleWrapper carrierConfig) { + final int[] timeoutMinuteList; + + if (carrierConfig != null) { + timeoutMinuteList = + carrierConfig.getIntArray( + VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY, + PENALTY_TIMEOUT_MINUTES_DEFAULT); + } else { + timeoutMinuteList = PENALTY_TIMEOUT_MINUTES_DEFAULT; + } + + // TODO: Add the support of back-off timeouts and return the full list + return TimeUnit.MINUTES.toMillis(timeoutMinuteList[0]); + } + + private void handleValidationResult() { + final boolean wasPenalized = mIsPenalized; + mIsPenalized = false; + for (NetworkMetricMonitor monitor : mMetricMonitors) { + mIsPenalized |= monitor.isValidationFailed(); + } + + if (wasPenalized == mIsPenalized) { + return; + } + + logInfo( + "#handleValidationResult: wasPenalized " + + wasPenalized + + " mIsPenalized " + + mIsPenalized); + + if (mIsPenalized) { + mHandler.postDelayed( + new ExitPenaltyBoxRunnable(), mCancellationToken, mPenalizedTimeoutMs); + } else { + // Exit the penalty box + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + } + mEvaluatorCallback.onEvaluationResultChanged(); + } + + public class ExitPenaltyBoxRunnable implements Runnable { + @Override + public void run() { + if (!mIsPenalized) { + logWtf("Evaluator not being penalized but ExitPenaltyBoxRunnable was scheduled"); + return; + } + + // TODO: There might be a future metric monitor (e.g. ping) that will require the + // validation to pass before exiting the penalty box. + mIsPenalized = false; + mEvaluatorCallback.onEvaluationResultChanged(); + } + } + + /** Set the NetworkCapabilities */ + public void setNetworkCapabilities( + @NonNull NetworkCapabilities nc, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setNetworkCapabilities(nc); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set the LinkProperties */ + public void setLinkProperties( + @NonNull LinkProperties lp, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setLinkProperties(lp); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set whether the network is blocked */ + public void setIsBlocked( + boolean isBlocked, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mNetworkRecordBuilder.setIsBlocked(isBlocked); + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + } + + /** Set whether the network is selected as VCN's underlying network */ + public void setIsSelected( + boolean isSelected, + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + mIsSelected = isSelected; + + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setIsSelectedUnderlyingNetwork(isSelected); + } + } + + /** + * Update the last TelephonySubscriptionSnapshot and carrier config to reevaluate the network + */ + public void reevaluate( + @NonNull List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + @NonNull ParcelUuid subscriptionGroup, + @NonNull TelephonySubscriptionSnapshot lastSnapshot, + @Nullable PersistableBundleWrapper carrierConfig) { + updatePriorityClass( + underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); + + // The already scheduled event will not be affected. The followup events will be scheduled + // with the new timeout + mPenalizedTimeoutMs = getPenaltyTimeoutMs(carrierConfig); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setCarrierConfig(carrierConfig); + } + } + + /** Update the inbound IpSecTransform applied to the network */ + public void setInboundTransform(@NonNull IpSecTransform transform) { + if (!mIsSelected) { + logWtf("setInboundTransform on an unselected evaluator"); + return; + } + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.setInboundTransform(transform); + } + } + + /** Close the evaluator and stop all the underlying network metric monitors */ + public void close() { + mHandler.removeCallbacksAndEqualMessages(mCancellationToken); + + for (NetworkMetricMonitor monitor : mMetricMonitors) { + monitor.close(); + } + } + + /** Return whether this network evaluator is valid */ + public boolean isValid() { + return mNetworkRecordBuilder.isValid(); + } + + /** Return the network */ + public Network getNetwork() { + return mNetworkRecordBuilder.getNetwork(); + } + + /** Return the network record */ + public UnderlyingNetworkRecord getNetworkRecord() { + return mNetworkRecordBuilder.build(); + } + + /** Return the priority class for network selection */ + public int getPriorityClass() { + return mPriorityClass; + } + + /** Return whether the network is being penalized */ + public boolean isPenalized() { + return mIsPenalized; + } + + /** Dump the information of this instance */ + public void dump(IndentingPrintWriter pw) { + pw.println("UnderlyingNetworkEvaluator:"); + pw.increaseIndent(); + + if (mNetworkRecordBuilder.isValid()) { + getNetworkRecord().dump(pw); + } else { + pw.println( + "UnderlyingNetworkRecord incomplete: mNetwork: " + + mNetworkRecordBuilder.getNetwork()); + } + + pw.println("mIsSelected: " + mIsSelected); + pw.println("mPriorityClass: " + mPriorityClass); + pw.println("mIsPenalized: " + mIsPenalized); + + pw.decreaseIndent(); + } + + private String getLogPrefix() { + return "[Network " + mNetworkRecordBuilder.getNetwork() + "] "; + } + + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[INFO ] " + TAG + getLogPrefix() + msg); + } + + private void logWtf(String msg) { + Slog.wtf(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[WTF ] " + TAG + getLogPrefix() + msg); + } +} diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index aea9f4d2dbae..7ab8e552722a 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -16,24 +16,17 @@ package com.android.server.vcn.routeselection; -import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import android.annotation.NonNull; import android.annotation.Nullable; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; -import android.net.vcn.VcnUnderlyingNetworkTemplate; -import android.os.ParcelUuid; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.internal.util.IndentingPrintWriter; -import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.VcnContext; -import java.util.Comparator; -import java.util.List; import java.util.Objects; /** @@ -46,54 +39,17 @@ public class UnderlyingNetworkRecord { @NonNull public final NetworkCapabilities networkCapabilities; @NonNull public final LinkProperties linkProperties; public final boolean isBlocked; - public final boolean isSelected; - public final int priorityClass; @VisibleForTesting(visibility = Visibility.PRIVATE) public UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, - boolean isBlocked, - VcnContext vcnContext, - List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + boolean isBlocked) { this.network = network; this.networkCapabilities = networkCapabilities; this.linkProperties = linkProperties; this.isBlocked = isBlocked; - - this.isSelected = isSelected(this.network, currentlySelected); - - priorityClass = - NetworkPriorityClassifier.calculatePriorityClass( - vcnContext, - this, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); - } - - @VisibleForTesting(visibility = Visibility.PRIVATE) - public UnderlyingNetworkRecord( - @NonNull Network network, - @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, - boolean isBlocked, - boolean isSelected, - int priorityClass) { - this.network = network; - this.networkCapabilities = networkCapabilities; - this.linkProperties = linkProperties; - this.isBlocked = isBlocked; - this.isSelected = isSelected; - - this.priorityClass = priorityClass; } @Override @@ -113,64 +69,20 @@ public class UnderlyingNetworkRecord { return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); } - /** Returns if two records are equal including their priority classes. */ - public static boolean isEqualIncludingPriorities( - UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) { - if (left != null && right != null) { - return left.equals(right) - && left.isSelected == right.isSelected - && left.priorityClass == right.priorityClass; - } - - return left == right; - } - - static Comparator<UnderlyingNetworkRecord> getComparator() { - return (left, right) -> { - final int leftIndex = left.priorityClass; - final int rightIndex = right.priorityClass; - - // In the case of networks in the same priority class, prioritize based on other - // criteria (eg. actively selected network, link metrics, etc) - if (leftIndex == rightIndex) { - // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord - // fall into the same priority class. - if (left.isSelected) { - return -1; - } - if (right.isSelected) { - return 1; - } - } - return Integer.compare(leftIndex, rightIndex); - }; - } - - private static boolean isSelected( - Network networkToCheck, UnderlyingNetworkRecord currentlySelected) { - if (currentlySelected == null) { - return false; - } - if (currentlySelected.network.equals(networkToCheck)) { - return true; - } - return false; + /** Return whether two records represent the same network */ + public static boolean isSameNetwork( + @Nullable UnderlyingNetworkRecord leftRecord, + @Nullable UnderlyingNetworkRecord rightRecord) { + final Network left = leftRecord == null ? null : leftRecord.network; + final Network right = rightRecord == null ? null : rightRecord.network; + return Objects.equals(left, right); } /** Dumps the state of this record for logging and debugging purposes. */ - void dump( - VcnContext vcnContext, - IndentingPrintWriter pw, - List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + void dump(IndentingPrintWriter pw) { pw.println("UnderlyingNetworkRecord:"); pw.increaseIndent(); - pw.println("priorityClass: " + priorityClass); - pw.println("isSelected: " + isSelected); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); @@ -218,29 +130,14 @@ public class UnderlyingNetworkRecord { return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; } - UnderlyingNetworkRecord build( - VcnContext vcnContext, - List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, - ParcelUuid subscriptionGroup, - TelephonySubscriptionSnapshot snapshot, - UnderlyingNetworkRecord currentlySelected, - PersistableBundleWrapper carrierConfig) { + UnderlyingNetworkRecord build() { if (!isValid()) { throw new IllegalArgumentException( "Called build before UnderlyingNetworkRecord was valid"); } return new UnderlyingNetworkRecord( - mNetwork, - mNetworkCapabilities, - mLinkProperties, - mIsBlocked, - vcnContext, - underlyingNetworkTemplates, - subscriptionGroup, - snapshot, - currentlySelected, - carrierConfig); + mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); } } } diff --git a/services/core/java/com/android/server/wearable/OWNERS b/services/core/java/com/android/server/wearable/OWNERS index 073e2d79850b..eca48b742cef 100644 --- a/services/core/java/com/android/server/wearable/OWNERS +++ b/services/core/java/com/android/server/wearable/OWNERS @@ -1,3 +1 @@ -charliewang@google.com -oni@google.com -volnov@google.com
\ No newline at end of file +include /core/java/android/app/wearable/OWNERS
\ No newline at end of file diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java index cd48f5d527c1..106be5f124a0 100644 --- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java +++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java @@ -218,7 +218,7 @@ public class WearableSensingManagerService extends PersistableBundle data, SharedMemory sharedMemory, RemoteCallback callback) { - Slog.i(TAG, "WearableSensingManagerInternal provideData."); + Slog.d(TAG, "WearableSensingManagerInternal provideData."); Objects.requireNonNull(data); Objects.requireNonNull(callback); mContext.enforceCallingOrSelfPermission( diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java index 05da9dfe7921..e5c743cc69e4 100644 --- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java +++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; + import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -180,16 +181,8 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, if (snapshot == null) { return null; } - final HardwareBuffer buffer = snapshot.getHardwareBuffer(); - if (buffer.getWidth() == 0 || buffer.getHeight() == 0) { - buffer.close(); - Slog.e(TAG, "Invalid snapshot dimensions " + buffer.getWidth() + "x" - + buffer.getHeight()); - return null; - } else { - mCache.putSnapshot(source, snapshot); - return snapshot; - } + mCache.putSnapshot(source, snapshot); + return snapshot; } @VisibleForTesting @@ -210,6 +203,11 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, @Nullable TaskSnapshot snapshot(TYPE source) { + return snapshot(source, mHighResSnapshotScale); + } + + @Nullable + TaskSnapshot snapshot(TYPE source, float scale) { TaskSnapshot.Builder builder = new TaskSnapshot.Builder(); final Rect crop = prepareTaskSnapshot(source, builder); if (crop == null) { @@ -218,7 +216,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, } Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "createSnapshot"); final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = createSnapshot(source, - mHighResSnapshotScale, crop, builder); + scale, crop, builder); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); if (screenshotBuffer == null) { // Failed to acquire image. Has been logged. @@ -227,7 +225,19 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, builder.setCaptureTime(SystemClock.elapsedRealtimeNanos()); builder.setSnapshot(screenshotBuffer.getHardwareBuffer()); builder.setColorSpace(screenshotBuffer.getColorSpace()); - return builder.build(); + final TaskSnapshot snapshot = builder.build(); + return validateSnapshot(snapshot); + } + + private static TaskSnapshot validateSnapshot(@NonNull TaskSnapshot snapshot) { + final HardwareBuffer buffer = snapshot.getHardwareBuffer(); + if (buffer.getWidth() == 0 || buffer.getHeight() == 0) { + buffer.close(); + Slog.e(TAG, "Invalid snapshot dimensions " + buffer.getWidth() + "x" + + buffer.getHeight()); + return null; + } + return snapshot; } @Nullable @@ -432,7 +442,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, InsetUtils.addInsets(contentInsets, letterboxInsets); // Note, the app theme snapshot is never translucent because we enforce a non-translucent // color above - return new TaskSnapshot( + final TaskSnapshot taskSnapshot = new TaskSnapshot( System.currentTimeMillis() /* id */, SystemClock.elapsedRealtimeNanos() /* captureTime */, topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(), @@ -441,6 +451,7 @@ abstract class AbsAppSnapshotController<TYPE extends WindowContainer, contentInsets, letterboxInsets, false /* isLowResolution */, false /* isRealSnapshot */, source.getWindowingMode(), getAppearance(source), false /* isTranslucent */, false /* hasImeSurface */); + return validateSnapshot(taskSnapshot); } static Rect getSystemBarInsets(Rect frame, InsetsState state) { diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java index 4b55bec928c7..676203bc746a 100644 --- a/services/core/java/com/android/server/wm/ActivityClientController.java +++ b/services/core/java/com/android/server/wm/ActivityClientController.java @@ -1166,11 +1166,12 @@ class ActivityClientController extends IActivityClientController.Stub { transition.abort(); return; } - transition.collect(topFocusedRootTask); - executeMultiWindowFullscreenRequest(fullscreenRequest, topFocusedRootTask); - r.mTransitionController.requestStartTransition(transition, topFocusedRootTask, + final Task requestingTask = r.getTask(); + transition.collect(requestingTask); + executeMultiWindowFullscreenRequest(fullscreenRequest, requestingTask); + r.mTransitionController.requestStartTransition(transition, requestingTask, null /* remoteTransition */, null /* displayChange */); - transition.setReady(topFocusedRootTask, true); + transition.setReady(requestingTask, true); } private static void reportMultiwindowFullscreenRequestValidatingResult(IRemoteCallback callback, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 3a792d079db2..69fbe6ba3c29 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -168,6 +168,7 @@ 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_USER_FULLSCREEN_OVERRIDE_ENABLED; import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; import static com.android.server.wm.ActivityRecordProto.LAST_DROP_INPUT_MODE; @@ -182,6 +183,7 @@ import static com.android.server.wm.ActivityRecordProto.PROC_ID; import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS; import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN; import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE; +import static com.android.server.wm.ActivityRecordProto.SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS; import static com.android.server.wm.ActivityRecordProto.SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT; import static com.android.server.wm.ActivityRecordProto.SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP; import static com.android.server.wm.ActivityRecordProto.SHOULD_OVERRIDE_FORCE_RESIZE_APP; @@ -10338,6 +10340,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLetterboxUiController.shouldIgnoreOrientationRequestLoop()); proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP, mLetterboxUiController.shouldOverrideForceResizeApp()); + proto.write(SHOULD_ENABLE_USER_ASPECT_RATIO_SETTINGS, + mLetterboxUiController.shouldEnableUserAspectRatioSettings()); + proto.write(IS_USER_FULLSCREEN_OVERRIDE_ENABLED, + mLetterboxUiController.isUserFullscreenOverrideEnabled()); } @Override diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java index 7af494c296de..a692167bbbf9 100644 --- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java +++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java @@ -25,6 +25,7 @@ import android.os.Environment; import android.os.SystemProperties; import android.os.Trace; import android.util.ArraySet; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.window.TaskSnapshot; @@ -36,6 +37,7 @@ import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider; import com.android.window.flags.Flags; import java.io.File; +import java.io.PrintWriter; import java.util.ArrayList; /** @@ -136,11 +138,26 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord false /* enableLowResSnapshots */, 0 /* lowResScaleFactor */, use16BitFormat); } - /** Retrieves a snapshot for an activity from cache. */ + /** + * Retrieves a snapshot for a set of activities from cache. + * This will only return the snapshot IFF input activities exist entirely in the snapshot. + * Sample: If the snapshot was captured with activity A and B, here will return null if the + * input activity is only [A] or [B], it must be [A, B] + */ @Nullable - TaskSnapshot getSnapshot(ActivityRecord ar) { - final int code = getSystemHashCode(ar); - return mCache.getSnapshot(code); + TaskSnapshot getSnapshot(@NonNull ActivityRecord[] activities) { + if (activities.length == 0) { + return null; + } + final UserSavedFile tmpUsf = findSavedFile(activities[0]); + if (tmpUsf == null || tmpUsf.mActivityIds.size() != activities.length) { + return null; + } + int fileId = 0; + for (int i = activities.length - 1; i >= 0; --i) { + fileId ^= getSystemHashCode(activities[i]); + } + return tmpUsf.mFileId == fileId ? mCache.getSnapshot(tmpUsf.mActivityIds.get(0)) : null; } private void cleanUpUserFiles(int userId) { @@ -229,33 +246,16 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord + " load " + mPendingLoadActivity); } // load snapshot to cache - for (int i = mPendingLoadActivity.size() - 1; i >= 0; i--) { - final ActivityRecord ar = mPendingLoadActivity.valueAt(i); - final int code = getSystemHashCode(ar); - final int userId = ar.mUserId; - if (mCache.getSnapshot(code) != null) { - // already in cache, skip - continue; - } - if (containsFile(code, userId)) { - synchronized (mSnapshotPersistQueue.getLock()) { - mSnapshotPersistQueue.insertQueueAtFirstLocked( - new LoadActivitySnapshotItem(ar, code, userId, mPersistInfoProvider)); - } - } - } + loadActivitySnapshot(); // clear mTmpRemoveActivity from cache for (int i = mPendingRemoveActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingRemoveActivity.valueAt(i); - final int code = getSystemHashCode(ar); - mCache.onIdRemoved(code); + removeCachedFiles(ar); } // clear snapshot on cache and delete files for (int i = mPendingDeleteActivity.size() - 1; i >= 0; i--) { final ActivityRecord ar = mPendingDeleteActivity.valueAt(i); - final int code = getSystemHashCode(ar); - mCache.onIdRemoved(code); - removeIfUserSavedFileExist(code, ar.mUserId); + removeIfUserSavedFileExist(ar); } // don't keep any reference resetTmpFields(); @@ -264,28 +264,38 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord class LoadActivitySnapshotItem extends SnapshotPersistQueue.WriteQueueItem { private final int mCode; private final int mUserId; - private final ActivityRecord mActivityRecord; + private final ActivityRecord[] mActivities; - LoadActivitySnapshotItem(@NonNull ActivityRecord ar, int code, int userId, + LoadActivitySnapshotItem(@NonNull ActivityRecord[] activities, int code, int userId, @NonNull PersistInfoProvider persistInfoProvider) { super(persistInfoProvider); - mActivityRecord = ar; + mActivities = activities; mCode = code; mUserId = userId; } @Override void write() { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, - "load_activity_snapshot"); - final TaskSnapshot snapshot = mSnapshotLoader.loadTask(mCode, - mUserId, false /* loadLowResolutionBitmap */); - synchronized (mService.getWindowManagerLock()) { - if (snapshot != null && !mActivityRecord.finishing) { - mCache.putSnapshot(mActivityRecord, snapshot); + try { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, + "load_activity_snapshot"); + final TaskSnapshot snapshot = mSnapshotLoader.loadTask(mCode, + mUserId, false /* loadLowResolutionBitmap */); + if (snapshot == null) { + return; + } + synchronized (mService.getWindowManagerLock()) { + // Verify the snapshot is still needed, and the activity is not finishing + if (!hasRecord(mActivities[0])) { + return; + } + for (ActivityRecord ar : mActivities) { + mCache.putSnapshot(ar, snapshot); + } } + } finally { + Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } - Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } @Override @@ -297,18 +307,81 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } } - void recordSnapshot(ActivityRecord activity) { - if (shouldDisableSnapshots()) { + void loadActivitySnapshot() { + if (mPendingLoadActivity.isEmpty()) { + return; + } + // Only load if saved file exists. + final ArraySet<UserSavedFile> loadingFiles = new ArraySet<>(); + for (int i = mPendingLoadActivity.size() - 1; i >= 0; i--) { + final ActivityRecord ar = mPendingLoadActivity.valueAt(i); + final UserSavedFile usf = findSavedFile(ar); + if (usf != null) { + loadingFiles.add(usf); + } + } + // Filter out the activity if the snapshot was removed. + for (int i = loadingFiles.size() - 1; i >= 0; i--) { + final UserSavedFile usf = loadingFiles.valueAt(i); + final ActivityRecord[] activities = usf.filterExistActivities(mPendingLoadActivity); + if (activities == null) { + continue; + } + if (getSnapshot(activities) != null) { + // Found the cache in memory, so skip loading from file. + continue; + } + loadSnapshotInner(activities, usf); + } + } + + @VisibleForTesting + void loadSnapshotInner(ActivityRecord[] activities, UserSavedFile usf) { + synchronized (mSnapshotPersistQueue.getLock()) { + mSnapshotPersistQueue.insertQueueAtFirstLocked(new LoadActivitySnapshotItem( + activities, usf.mFileId, usf.mUserId, mPersistInfoProvider)); + } + } + + /** + * Record one or multiple activities within a snapshot where those activities must belong to + * the same task. + * @param activity If the request activity is more than one, try to record those activities + * as a single snapshot, so those activities should belong to the same task. + */ + void recordSnapshot(@NonNull ArrayList<ActivityRecord> activity) { + if (shouldDisableSnapshots() || activity.isEmpty()) { return; } if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#recordSnapshot " + activity); } - final TaskSnapshot snapshot = recordSnapshotInner(activity); - if (snapshot != null) { - final int code = getSystemHashCode(activity); - addUserSavedFile(code, activity.mUserId, snapshot); + final int size = activity.size(); + final int[] mixedCode = new int[size]; + if (size == 1) { + final ActivityRecord singleActivity = activity.get(0); + final TaskSnapshot snapshot = recordSnapshotInner(singleActivity); + if (snapshot != null) { + mixedCode[0] = getSystemHashCode(singleActivity); + addUserSavedFile(singleActivity.mUserId, snapshot, mixedCode); + } + return; } + + final Task mainTask = activity.get(0).getTask(); + // Snapshot by task controller with activity's scale. + final TaskSnapshot snapshot = mService.mTaskSnapshotController + .snapshot(mainTask, mHighResSnapshotScale); + if (snapshot == null) { + return; + } + + for (int i = 0; i < activity.size(); ++i) { + final ActivityRecord next = activity.get(i); + mCache.putSnapshot(next, snapshot); + mixedCode[i] = getSystemHashCode(next); + } + addUserSavedFile(mainTask.mUserId, snapshot, mixedCode); } /** @@ -331,7 +404,8 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } } - private static int getSystemHashCode(ActivityRecord activity) { + @VisibleForTesting + static int getSystemHashCode(ActivityRecord activity) { return System.identityHashCode(activity); } @@ -362,7 +436,13 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (ar.isVisibleRequested()) { mPendingDeleteActivity.add(ar); // load next one if exists. - addBelowActivityIfExist(ar, mPendingLoadActivity, true, "load-snapshot"); + // Note if this transition is happen between two TaskFragment, the next N - 1 activity + // may not participant in this transition. + // Sample: + // [TF1] close + // [TF2] open + // Bottom Activity <- Able to load this even it didn't participant the transition. + addBelowActivityIfExist(ar, mPendingLoadActivity, false, "load-snapshot"); } else { // remove the snapshot for the one below close addBelowActivityIfExist(ar, mPendingRemoveActivity, true, "remove-snapshot"); @@ -478,10 +558,8 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } private void adjustSavedFileOrder(Task nextTopTask) { - final int userId = nextTopTask.mUserId; nextTopTask.forAllActivities(ar -> { - final int code = getSystemHashCode(ar); - final UserSavedFile usf = getUserFiles(userId).get(code); + final UserSavedFile usf = findSavedFile(ar); if (usf != null) { mSavedFilesInOrder.remove(usf); mSavedFilesInOrder.add(usf); @@ -494,9 +572,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (shouldDisableSnapshots()) { return; } - super.onAppRemoved(activity); - final int code = getSystemHashCode(activity); - removeIfUserSavedFileExist(code, activity.mUserId); + removeIfUserSavedFileExist(activity); if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#onAppRemoved delete snapshot " + activity); } @@ -507,9 +583,7 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord if (shouldDisableSnapshots()) { return; } - super.onAppDied(activity); - final int code = getSystemHashCode(activity); - removeIfUserSavedFileExist(code, activity.mUserId); + removeIfUserSavedFileExist(activity); if (DEBUG) { Slog.d(TAG, "ActivitySnapshotController#onAppDied delete snapshot " + activity); } @@ -558,55 +632,92 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord return mUserSavedFiles.get(userId); } - private void removeIfUserSavedFileExist(int code, int userId) { - final UserSavedFile usf = getUserFiles(userId).get(code); + UserSavedFile findSavedFile(@NonNull ActivityRecord ar) { + final int code = getSystemHashCode(ar); + return findSavedFile(ar.mUserId, code); + } + + UserSavedFile findSavedFile(int userId, int code) { + final SparseArray<UserSavedFile> usfs = getUserFiles(userId); + return usfs.get(code); + } + + private void removeCachedFiles(ActivityRecord ar) { + final UserSavedFile usf = findSavedFile(ar); + if (usf != null) { + for (int i = usf.mActivityIds.size() - 1; i >= 0; --i) { + final int activityId = usf.mActivityIds.get(i); + mCache.onIdRemoved(activityId); + } + } + } + + private void removeIfUserSavedFileExist(ActivityRecord ar) { + final UserSavedFile usf = findSavedFile(ar); if (usf != null) { - mUserSavedFiles.get(userId).remove(code); + final SparseArray<UserSavedFile> usfs = getUserFiles(ar.mUserId); + for (int i = usf.mActivityIds.size() - 1; i >= 0; --i) { + final int activityId = usf.mActivityIds.get(i); + usf.remove(activityId); + mCache.onIdRemoved(activityId); + usfs.remove(activityId); + } mSavedFilesInOrder.remove(usf); - mPersister.removeSnapshot(code, userId); + mPersister.removeSnapshot(usf.mFileId, ar.mUserId); } } - private boolean containsFile(int code, int userId) { - return getUserFiles(userId).get(code) != null; + @VisibleForTesting + boolean hasRecord(@NonNull ActivityRecord ar) { + return findSavedFile(ar) != null; } - private void addUserSavedFile(int code, int userId, TaskSnapshot snapshot) { - final SparseArray<UserSavedFile> savedFiles = getUserFiles(userId); - final UserSavedFile savedFile = savedFiles.get(code); - if (savedFile == null) { - final UserSavedFile usf = new UserSavedFile(code, userId); - savedFiles.put(code, usf); - mSavedFilesInOrder.add(usf); - mPersister.persistSnapshot(code, userId, snapshot); + @VisibleForTesting + void addUserSavedFile(int userId, TaskSnapshot snapshot, @NonNull int[] code) { + final UserSavedFile savedFile = findSavedFile(userId, code[0]); + if (savedFile != null) { + Slog.w(TAG, "Duplicate request for recording activity snapshot " + savedFile); + return; + } + int fileId = 0; + for (int i = code.length - 1; i >= 0; --i) { + fileId ^= code[i]; + } + final UserSavedFile usf = new UserSavedFile(fileId, userId); + SparseArray<UserSavedFile> usfs = getUserFiles(userId); + for (int i = code.length - 1; i >= 0; --i) { + usfs.put(code[i], usf); + } + usf.mActivityIds.addAll(code); + mSavedFilesInOrder.add(usf); + mPersister.persistSnapshot(fileId, userId, snapshot); - if (mSavedFilesInOrder.size() > MAX_PERSIST_SNAPSHOT_COUNT * 2) { - purgeSavedFile(); - } + if (mSavedFilesInOrder.size() > MAX_PERSIST_SNAPSHOT_COUNT * 2) { + purgeSavedFile(); } } private void purgeSavedFile() { final int savedFileCount = mSavedFilesInOrder.size(); final int removeCount = savedFileCount - MAX_PERSIST_SNAPSHOT_COUNT; - final ArrayList<UserSavedFile> usfs = new ArrayList<>(); - if (removeCount > 0) { - final int removeTillIndex = savedFileCount - removeCount; - for (int i = savedFileCount - 1; i > removeTillIndex; --i) { - final UserSavedFile usf = mSavedFilesInOrder.remove(i); - if (usf != null) { - final SparseArray<UserSavedFile> records = getUserFiles(usf.mUserId); - records.remove(usf.mFileId); - usfs.add(usf); - } - } + if (removeCount < 1) { + return; } - if (usfs.size() > 0) { - removeSnapshotFiles(usfs); + + final ArrayList<UserSavedFile> removeTargets = new ArrayList<>(); + for (int i = removeCount - 1; i >= 0; --i) { + final UserSavedFile usf = mSavedFilesInOrder.remove(i); + final SparseArray<UserSavedFile> files = mUserSavedFiles.get(usf.mUserId); + for (int j = usf.mActivityIds.size() - 1; j >= 0; --j) { + mCache.removeRunningEntry(usf.mActivityIds.get(j)); + files.remove(usf.mActivityIds.get(j)); + } + removeTargets.add(usf); } + removeSnapshotFiles(removeTargets); } - private void removeSnapshotFiles(ArrayList<UserSavedFile> files) { + private void removeSnapshotFiles(@NonNull ArrayList<UserSavedFile> files) { synchronized (mSnapshotPersistQueue.getLock()) { mSnapshotPersistQueue.sendToQueueLocked( new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) { @@ -624,12 +735,85 @@ class ActivitySnapshotController extends AbsAppSnapshotController<ActivityRecord } } + @Override + void dump(PrintWriter pw, String prefix) { + super.dump(pw, prefix); + final String doublePrefix = prefix + " "; + final String triplePrefix = doublePrefix + " "; + for (int i = mUserSavedFiles.size() - 1; i >= 0; --i) { + final SparseArray<UserSavedFile> usfs = mUserSavedFiles.valueAt(i); + pw.println(doublePrefix + "UserSavedFile userId=" + mUserSavedFiles.keyAt(i)); + final ArraySet<UserSavedFile> sets = new ArraySet<>(); + for (int j = usfs.size() - 1; j >= 0; --j) { + sets.add(usfs.valueAt(j)); + } + for (int j = sets.size() - 1; j >= 0; --j) { + pw.println(triplePrefix + "SavedFile=" + sets.valueAt(j)); + } + } + } + static class UserSavedFile { - int mFileId; - int mUserId; + // The unique id as filename. + final int mFileId; + final int mUserId; + + /** + * The Id of all activities which are includes in the snapshot. + */ + final IntArray mActivityIds = new IntArray(); + UserSavedFile(int fileId, int userId) { mFileId = fileId; mUserId = userId; } + + boolean contains(int code) { + return mActivityIds.contains(code); + } + + void remove(int code) { + final int index = mActivityIds.indexOf(code); + if (index >= 0) { + mActivityIds.remove(index); + } + } + + ActivityRecord[] filterExistActivities( + @NonNull ArraySet<ActivityRecord> pendingLoadActivity) { + ArrayList<ActivityRecord> matchedActivities = null; + for (int i = pendingLoadActivity.size() - 1; i >= 0; --i) { + final ActivityRecord ar = pendingLoadActivity.valueAt(i); + if (contains(getSystemHashCode(ar))) { + if (matchedActivities == null) { + matchedActivities = new ArrayList<>(); + } + matchedActivities.add(ar); + } + } + if (matchedActivities == null || matchedActivities.size() != mActivityIds.size()) { + return null; + } + return matchedActivities.toArray(new ActivityRecord[0]); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(128); + sb.append("UserSavedFile{"); + sb.append(Integer.toHexString(System.identityHashCode(this))); + sb.append(" fileId="); + sb.append(Integer.toHexString(mFileId)); + sb.append(", activityIds=["); + for (int i = mActivityIds.size() - 1; i >= 0; --i) { + sb.append(Integer.toHexString(mActivityIds.get(i))); + if (i > 0) { + sb.append(','); + } + } + sb.append("]"); + sb.append("}"); + return sb.toString(); + } } } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 22d17b596c4c..8aaf76a165ab 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -1311,7 +1311,7 @@ class BackNavigationController { Rect insets; if (mainWindow != null) { insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets( - mBounds, WindowInsets.Type.systemBars(), + mBounds, WindowInsets.Type.tappableElement(), false /* ignoreVisibility */).toRect(); InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets()); } else { @@ -1327,7 +1327,8 @@ class BackNavigationController { return mAnimationTarget; } - void createStartingSurface(@NonNull WindowContainer closeWindow) { + void createStartingSurface(@NonNull WindowContainer closeWindow, + @NonNull ActivityRecord[] visibleOpenActivities) { if (!mIsOpen) { return; } @@ -1346,7 +1347,7 @@ class BackNavigationController { if (mainActivity == null) { return; } - final TaskSnapshot snapshot = getSnapshot(mTarget); + final TaskSnapshot snapshot = getSnapshot(mTarget, visibleOpenActivities); mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController .addWindowlessStartingSurface(openTask, mainActivity, // Choose configuration from closeWindow, because the configuration @@ -1489,7 +1490,8 @@ class BackNavigationController { // Try to draw two snapshot within a WindowlessStartingWindow, or find // another key for StartingWindowRecordManager. && openAnimationAdaptor.length == 1) { - openAnimationAdaptor[0].createStartingSurface(closeWindow); + openAnimationAdaptor[0].createStartingSurface(closeWindow, + visibleOpenActivities); } else { for (int i = visibleOpenActivities.length - 1; i >= 0; --i) { setLaunchBehind(visibleOpenActivities[i]); @@ -1594,7 +1596,9 @@ class BackNavigationController { // skip commitVisibility call in setVisibility cause the activity won't visible here. // Call it again to make sure the activity could be visible while handling the pending // animation. - activity.commitVisibility(true, true); + // Do not performLayout during prepare animation, because it could cause focus window + // change. Let that happen after the BackNavigationInfo has returned to shell. + activity.commitVisibility(true, false /* performLayout */); activity.mTransitionController.mSnapshotController .mActivitySnapshotController.addOnBackPressedActivity(activity); } @@ -1671,7 +1675,8 @@ class BackNavigationController { mPendingAnimationBuilder = null; } - static TaskSnapshot getSnapshot(@NonNull WindowContainer w) { + static TaskSnapshot getSnapshot(@NonNull WindowContainer w, + ActivityRecord[] visibleOpenActivities) { if (w.asTask() != null) { final Task task = w.asTask(); return task.mRootWindowContainer.mWindowManager.mTaskSnapshotController.getSnapshot( @@ -1681,7 +1686,8 @@ class BackNavigationController { if (w.asActivityRecord() != null) { final ActivityRecord ar = w.asActivityRecord(); - return ar.mWmService.mSnapshotController.mActivitySnapshotController.getSnapshot(ar); + return ar.mWmService.mSnapshotController.mActivitySnapshotController + .getSnapshot(visibleOpenActivities); } return null; } diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index fc3a33883de6..9c9cf04de3cc 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -120,38 +120,56 @@ public class BackgroundActivityStartController { static final int BAL_BLOCK = 0; - static final int BAL_ALLOW_DEFAULT = 1; + static final int BAL_ALLOW_DEFAULT = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_DEFAULT; // Following codes are in order of precedence /** Important UIDs which should be always allowed to launch activities */ - static final int BAL_ALLOW_ALLOWLISTED_UID = 2; + static final int BAL_ALLOW_ALLOWLISTED_UID = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_ALLOWLISTED_UID; /** Apps that fulfill a certain role that can can always launch new tasks */ - static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = 3; + static final int BAL_ALLOW_ALLOWLISTED_COMPONENT = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_ALLOWLISTED_COMPONENT; - /** Apps which currently have a visible window or are bound by a service with a visible - * window */ - static final int BAL_ALLOW_VISIBLE_WINDOW = 4; + /** + * Apps which currently have a visible window or are bound by a service with a visible + * window + */ + static final int BAL_ALLOW_VISIBLE_WINDOW = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_VISIBLE_WINDOW; /** Allowed due to the PendingIntent sender */ - static final int BAL_ALLOW_PENDING_INTENT = 5; + static final int BAL_ALLOW_PENDING_INTENT = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_PENDING_INTENT; - /** App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges - * granted to it */ - static final int BAL_ALLOW_PERMISSION = 6; + /** + * App has START_ACTIVITIES_FROM_BACKGROUND permission or BAL instrumentation privileges + * granted to it + */ + static final int BAL_ALLOW_PERMISSION = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_BAL_PERMISSION; /** Process has SYSTEM_ALERT_WINDOW permission granted to it */ - static final int BAL_ALLOW_SAW_PERMISSION = 7; + static final int BAL_ALLOW_SAW_PERMISSION = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_SAW_PERMISSION; /** App is in grace period after an activity was started or finished */ - static final int BAL_ALLOW_GRACE_PERIOD = 8; + static final int BAL_ALLOW_GRACE_PERIOD = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_GRACE_PERIOD; /** App is in a foreground task or bound to a foreground service (but not itself visible) */ - static final int BAL_ALLOW_FOREGROUND = 9; + static final int BAL_ALLOW_FOREGROUND = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_FOREGROUND; /** Process belongs to a SDK sandbox */ - static final int BAL_ALLOW_SDK_SANDBOX = 10; + static final int BAL_ALLOW_SDK_SANDBOX = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_SDK_SANDBOX; + + /** Process belongs to a SDK sandbox */ + static final int BAL_ALLOW_NON_APP_VISIBLE_WINDOW = + FrameworkStatsLog.BAL_ALLOWED__ALLOWED_REASON__BAL_ALLOW_NON_APP_VISIBLE_WINDOW; static String balCodeToString(@BalCode int balCode) { return switch (balCode) { @@ -160,6 +178,7 @@ public class BackgroundActivityStartController { case BAL_ALLOW_DEFAULT -> "BAL_ALLOW_DEFAULT"; case BAL_ALLOW_FOREGROUND -> "BAL_ALLOW_FOREGROUND"; case BAL_ALLOW_GRACE_PERIOD -> "BAL_ALLOW_GRACE_PERIOD"; + case BAL_ALLOW_NON_APP_VISIBLE_WINDOW -> "BAL_ALLOW_NON_APP_VISIBLE_WINDOW"; case BAL_ALLOW_PENDING_INTENT -> "BAL_ALLOW_PENDING_INTENT"; case BAL_ALLOW_PERMISSION -> "BAL_ALLOW_PERMISSION"; case BAL_ALLOW_SAW_PERMISSION -> "BAL_ALLOW_SAW_PERMISSION"; @@ -788,7 +807,7 @@ public class BackgroundActivityStartController { /*background*/ false, "callingUid has visible window"); } if (mService.mActiveUids.hasNonAppVisibleWindow(callingUid)) { - return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, + return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW, /*background*/ false, "callingUid has non-app visible window"); } @@ -884,7 +903,7 @@ public class BackgroundActivityStartController { /*background*/ false, "realCallingUid has visible window"); } if (mService.mActiveUids.hasNonAppVisibleWindow(state.mRealCallingUid)) { - return new BalVerdict(BAL_ALLOW_VISIBLE_WINDOW, + return new BalVerdict(BAL_ALLOW_NON_APP_VISIBLE_WINDOW, /*background*/ false, "realCallingUid has non-app visible window"); } } else { @@ -989,7 +1008,8 @@ public class BackgroundActivityStartController { || balCode == BAL_ALLOW_PERMISSION || balCode == BAL_ALLOW_PENDING_INTENT || balCode == BAL_ALLOW_SAW_PERMISSION - || balCode == BAL_ALLOW_VISIBLE_WINDOW) { + || balCode == BAL_ALLOW_VISIBLE_WINDOW + || balCode == BAL_ALLOW_NON_APP_VISIBLE_WINDOW) { return true; } } @@ -1501,7 +1521,8 @@ public class BackgroundActivityStartController { Intent intent = state.mIntent; if (code == BAL_ALLOW_PENDING_INTENT - && (callingUid == Process.SYSTEM_UID || realCallingUid == Process.SYSTEM_UID)) { + && (callingUid < Process.FIRST_APPLICATION_UID + || realCallingUid < Process.FIRST_APPLICATION_UID)) { String activityName = intent != null ? requireNonNull(intent.getComponent()).flattenToShortString() : ""; writeBalAllowedLog(activityName, BAL_ALLOW_PENDING_INTENT, diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index bf30af3e8596..8035a298e45a 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -112,7 +112,7 @@ final class InputMonitor { * z-layering reference so that we can place the recents input consumer above it. */ private WeakReference<ActivityRecord> mActiveRecentsActivity = null; - private WeakReference<ActivityRecord> mActiveRecentsLayerRef = null; + private WeakReference<Task> mActiveRecentsLayerRef = null; private class UpdateInputWindows implements Runnable { @Override @@ -389,9 +389,9 @@ final class InputMonitor { /** * Inform InputMonitor when recents is active so it can enable the recents input consumer. * @param activity The active recents activity. {@code null} means recents is not active. - * @param layer An activity whose Z-layer is used as a reference for how to sort the consumer. + * @param layer A task whose Z-layer is used as a reference for how to sort the consumer. */ - void setActiveRecents(@Nullable ActivityRecord activity, @Nullable ActivityRecord layer) { + void setActiveRecents(@Nullable ActivityRecord activity, @Nullable Task layer) { final boolean clear = activity == null; final boolean wasActive = mActiveRecentsActivity != null && mActiveRecentsLayerRef != null; mActiveRecentsActivity = clear ? null : new WeakReference<>(activity); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 47972b37d836..fcc1e5b62221 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -1187,16 +1187,23 @@ final class LetterboxUiController { && mUserAspectRatio != USER_MIN_ASPECT_RATIO_FULLSCREEN; } - boolean shouldApplyUserFullscreenOverride() { + boolean isUserFullscreenOverrideEnabled() { if (FALSE.equals(mBooleanPropertyAllowUserAspectRatioOverride) || FALSE.equals(mBooleanPropertyAllowUserAspectRatioFullscreenOverride) || !mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled()) { return false; } + return true; + } - mUserAspectRatio = getUserMinAspectRatioOverrideCode(); + boolean shouldApplyUserFullscreenOverride() { + if (isUserFullscreenOverrideEnabled()) { + mUserAspectRatio = getUserMinAspectRatioOverrideCode(); - return mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN; + return mUserAspectRatio == USER_MIN_ASPECT_RATIO_FULLSCREEN; + } + + return false; } boolean isSystemOverrideToFullscreenEnabled() { diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6033220e260d..02b3f15979ce 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -808,7 +808,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents(); mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents(); mWmService.mSyncEngine.onSurfacePlacement(); - mWmService.mAnimator.executeAfterPrepareSurfacesRunnables(); checkAppTransitionReady(surfacePlacer); diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index ed54ea8229fe..f10a733040ed 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -75,6 +75,7 @@ import android.view.InsetsState; import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; +import android.view.View.FocusDirection; import android.view.WindowInsets; import android.view.WindowInsets.Type.InsetsType; import android.view.WindowManager; @@ -1000,6 +1001,17 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } return didTransfer; } + + @Override + public boolean moveFocusToAdjacentWindow(IWindow fromWindow, @FocusDirection int direction) { + final long identity = Binder.clearCallingIdentity(); + try { + return mService.moveFocusToAdjacentWindow(this, fromWindow, direction); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) { diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java index b6f040a6cb56..3014f979aa70 100644 --- a/services/core/java/com/android/server/wm/SnapshotController.java +++ b/services/core/java/com/android/server/wm/SnapshotController.java @@ -160,9 +160,7 @@ class SnapshotController { if (!allOpensOptInOnBackInvoked() || mCloseActivities.isEmpty()) { return; } - for (int i = mCloseActivities.size() - 1; i >= 0; --i) { - controller.recordSnapshot(mCloseActivities.get(i)); - } + controller.recordSnapshot(mCloseActivities); } } } diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java index bffdf54e17ce..e4379b5343f3 100644 --- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java +++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java @@ -274,7 +274,9 @@ class SnapshotPersistQueue { @Override void write() { - Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem"); + if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) { + Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem#" + mId); + } if (!mPersistInfoProvider.createDirectory(mUserId)) { Slog.e(TAG, "Unable to create snapshot directory for user dir=" + mPersistInfoProvider.getDirectory(mUserId)); diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index e1bf8f8aa34a..f620a9743eb4 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1933,29 +1933,29 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { dc.getInputMonitor().getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION); ActivityRecord recentsActivity = null; if (recentsAnimationInputConsumer != null) { - // find the top-most going-away activity and the recents activity. The top-most + // Find the top-most going-away task and the recents activity. The top-most // is used as layer reference while the recents is used for registering the consumer // override. - ActivityRecord topActivity = null; + Task topNonRecentsTask = null; for (int i = 0; i < info.getChanges().size(); ++i) { - final TransitionInfo.Change change = info.getChanges().get(i); - if (change.getTaskInfo() == null) continue; - final Task task = Task.fromWindowContainerToken( - info.getChanges().get(i).getTaskInfo().token); + final ActivityManager.RunningTaskInfo taskInfo = + info.getChanges().get(i).getTaskInfo(); + if (taskInfo == null) continue; + final Task task = Task.fromWindowContainerToken(taskInfo.token); if (task == null) continue; - final int activityType = change.getTaskInfo().topActivityType; + final int activityType = taskInfo.topActivityType; final boolean isRecents = activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS; if (isRecents && recentsActivity == null) { recentsActivity = task.getTopVisibleActivity(); - } else if (!isRecents && topActivity == null) { - topActivity = task.getTopNonFinishingActivity(); + } else if (!isRecents && topNonRecentsTask == null) { + topNonRecentsTask = task; } } - if (recentsActivity != null && topActivity != null) { + if (recentsActivity != null && topNonRecentsTask != null) { recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set( - topActivity.getBounds()); - dc.getInputMonitor().setActiveRecents(recentsActivity, topActivity); + topNonRecentsTask.getBounds()); + dc.getInputMonitor().setActiveRecents(recentsActivity, topNonRecentsTask); } } @@ -2020,16 +2020,17 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } mController.mNavigationBarAttachedToApp = false; - if (mRecentsDisplayId == INVALID_DISPLAY) { - Slog.e(TAG, "Reparented navigation bar without a valid display"); - mRecentsDisplayId = DEFAULT_DISPLAY; + int recentsDisplayId = mRecentsDisplayId; + if (recentsDisplayId == INVALID_DISPLAY) { + Slog.i(TAG, "Restore parent surface of navigation bar by another transition"); + recentsDisplayId = DEFAULT_DISPLAY; } final DisplayContent dc = - mController.mAtm.mRootWindowContainer.getDisplayContent(mRecentsDisplayId); + mController.mAtm.mRootWindowContainer.getDisplayContent(recentsDisplayId); final StatusBarManagerInternal bar = dc.getDisplayPolicy().getStatusBarManagerInternal(); if (bar != null) { - bar.setNavigationBarLumaSamplingEnabled(mRecentsDisplayId, true); + bar.setNavigationBarLumaSamplingEnabled(recentsDisplayId, true); } final WindowState navWindow = dc.getDisplayPolicy().getNavigationBar(); if (navWindow == null) return; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c63cc4373472..95448352736f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -287,6 +287,7 @@ import android.view.SurfaceControlViewHost; import android.view.SurfaceSession; import android.view.TaskTransitionSpec; import android.view.View; +import android.view.View.FocusDirection; import android.view.ViewDebug; import android.view.WindowContentFrameStats; import android.view.WindowInsets; @@ -9104,6 +9105,66 @@ public class WindowManagerService extends IWindowManager.Stub win.mClient); } + boolean moveFocusToAdjacentWindow(Session session, IWindow fromWindow, + @FocusDirection int direction) { + synchronized (mGlobalLock) { + final WindowState fromWin = windowForClientLocked(session, fromWindow, false); + if (fromWin == null || !fromWin.isFocused()) { + return false; + } + final TaskFragment fromFragment = fromWin.getTaskFragment(); + if (fromFragment == null) { + return false; + } + final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment(); + if (adjacentFragment == null || adjacentFragment.asTask() != null) { + // Don't move the focus to another task. + return false; + } + final Rect fromBounds = fromFragment.getBounds(); + final Rect adjacentBounds = adjacentFragment.getBounds(); + switch (direction) { + case View.FOCUS_LEFT: + if (adjacentBounds.left >= fromBounds.left) { + return false; + } + break; + case View.FOCUS_UP: + if (adjacentBounds.top >= fromBounds.top) { + return false; + } + break; + case View.FOCUS_RIGHT: + if (adjacentBounds.right <= fromBounds.right) { + return false; + } + break; + case View.FOCUS_DOWN: + if (adjacentBounds.bottom <= fromBounds.bottom) { + return false; + } + break; + case View.FOCUS_BACKWARD: + case View.FOCUS_FORWARD: + // These are not absolute directions. Skip checking the bounds. + break; + default: + return false; + } + final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity( + true /* focusableOnly */); + if (topRunningActivity == null) { + return false; + } + moveDisplayToTopInternal(topRunningActivity.getDisplayId()); + handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity); + if (fromWin.isFocused()) { + return false; + } + } + return true; + } + /** Return whether layer tracing is enabled */ public boolean isLayerTracing() { if (!checkCallingPermission( diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 59d0210251d1..0da0bb45eb9b 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -1034,8 +1034,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID); final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid); + if (transition != null) { + transition.deferTransitionReady(); + } waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents( caller.mPid, caller.mUid, taskId, safeOptions)); + if (transition != null) { + transition.continueTransitionReady(); + } break; } case HIERARCHY_OP_TYPE_REORDER: @@ -1113,11 +1119,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub activityOptions.setCallerDisplayId(DEFAULT_DISPLAY); } final Bundle options = activityOptions != null ? activityOptions.toBundle() : null; + if (transition != null) { + transition.deferTransitionReady(); + } int res = waitAsyncStart(() -> mService.mAmInternal.sendIntentSender( hop.getPendingIntent().getTarget(), hop.getPendingIntent().getWhitelistToken(), 0 /* code */, hop.getActivityIntent(), resolvedType, null /* finishReceiver */, null /* requiredPermission */, options)); + if (transition != null) { + transition.continueTransitionReady(); + } if (ActivityManager.isStartResultSuccessful(res)) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index afb0b20650f8..414339d3f349 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -299,7 +299,7 @@ public: void setSystemUiLightsOut(bool lightsOut); void setPointerDisplayId(int32_t displayId); void setPointerSpeed(int32_t speed); - void setPointerAcceleration(float acceleration); + void setMousePointerAccelerationEnabled(bool enabled); void setTouchpadPointerSpeed(int32_t speed); void setTouchpadNaturalScrollingEnabled(bool enabled); void setTouchpadTapToClickEnabled(bool enabled); @@ -411,8 +411,8 @@ private: // Pointer speed. int32_t pointerSpeed{0}; - // Pointer acceleration. - float pointerAcceleration{android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION}; + // True if pointer acceleration is enabled for mice. + bool mousePointerAccelerationEnabled{true}; // True if pointer gestures are enabled. bool pointerGesturesEnabled{true}; @@ -502,7 +502,8 @@ void NativeInputManager::dump(std::string& dump) { dump += StringPrintf(INDENT "System UI Lights Out: %s\n", toString(mLocked.systemUiLightsOut)); dump += StringPrintf(INDENT "Pointer Speed: %" PRId32 "\n", mLocked.pointerSpeed); - dump += StringPrintf(INDENT "Pointer Acceleration: %0.3f\n", mLocked.pointerAcceleration); + dump += StringPrintf(INDENT "Mouse Pointer Acceleration: %s\n", + mLocked.mousePointerAccelerationEnabled ? "Enabled" : "Disabled"); dump += StringPrintf(INDENT "Pointer Gestures Enabled: %s\n", toString(mLocked.pointerGesturesEnabled)); dump += StringPrintf(INDENT "Show Touches: %s\n", toString(mLocked.showTouches)); @@ -686,7 +687,10 @@ void NativeInputManager::getReaderConfiguration(InputReaderConfiguration* outCon outConfig->pointerVelocityControlParameters.scale = exp2f(mLocked.pointerSpeed * POINTER_SPEED_EXPONENT); - outConfig->pointerVelocityControlParameters.acceleration = mLocked.pointerAcceleration; + outConfig->pointerVelocityControlParameters.acceleration = + mLocked.mousePointerAccelerationEnabled + ? android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION + : 1; outConfig->pointerGesturesEnabled = mLocked.pointerGesturesEnabled; outConfig->showTouches = mLocked.showTouches; @@ -1207,16 +1211,16 @@ void NativeInputManager::setPointerSpeed(int32_t speed) { InputReaderConfiguration::Change::POINTER_SPEED); } -void NativeInputManager::setPointerAcceleration(float acceleration) { +void NativeInputManager::setMousePointerAccelerationEnabled(bool enabled) { { // acquire lock std::scoped_lock _l(mLock); - if (mLocked.pointerAcceleration == acceleration) { + if (mLocked.mousePointerAccelerationEnabled == enabled) { return; } - ALOGI("Setting pointer acceleration to %0.3f", acceleration); - mLocked.pointerAcceleration = acceleration; + ALOGI("Setting mouse pointer acceleration to %s", toString(enabled)); + mLocked.mousePointerAccelerationEnabled = enabled; } // release lock mInputManager->getReader().requestRefreshConfiguration( @@ -2174,10 +2178,11 @@ static void nativeSetPointerSpeed(JNIEnv* env, jobject nativeImplObj, jint speed im->setPointerSpeed(speed); } -static void nativeSetPointerAcceleration(JNIEnv* env, jobject nativeImplObj, jfloat acceleration) { +static void nativeSetMousePointerAccelerationEnabled(JNIEnv* env, jobject nativeImplObj, + jboolean enabled) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - im->setPointerAcceleration(acceleration); + im->setMousePointerAccelerationEnabled(enabled); } static void nativeSetTouchpadPointerSpeed(JNIEnv* env, jobject nativeImplObj, jint speed) { @@ -2812,7 +2817,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*)nativeTransferTouchFocus}, {"transferTouch", "(Landroid/os/IBinder;I)Z", (void*)nativeTransferTouch}, {"setPointerSpeed", "(I)V", (void*)nativeSetPointerSpeed}, - {"setPointerAcceleration", "(F)V", (void*)nativeSetPointerAcceleration}, + {"setMousePointerAccelerationEnabled", "(Z)V", + (void*)nativeSetMousePointerAccelerationEnabled}, {"setTouchpadPointerSpeed", "(I)V", (void*)nativeSetTouchpadPointerSpeed}, {"setTouchpadNaturalScrollingEnabled", "(Z)V", (void*)nativeSetTouchpadNaturalScrollingEnabled}, diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml index 070bd4b1c5a9..2ccd1e4c00c7 100644 --- a/services/core/lint-baseline.xml +++ b/services/core/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="5" by="lint 7.2.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NonUserGetterCalled" @@ -145,4 +145,4 @@ line="7158"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java index 69a5e5c3a901..db985fd16749 100644 --- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java @@ -50,7 +50,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_UNDEFINED, - callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); + callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp, + /*shouldBindClientToDeath=*/ true); } /** diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java index 31409ab1de4b..b24accbe3231 100644 --- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java @@ -63,7 +63,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_CREATE, - callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp); + callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp, + /*shouldBindClientToDeath=*/ true); mRequestSessionMetric.collectCreateFlowInitialMetricInfo( /*origin=*/request.getOrigin() != null, request); mPrimaryProviders = primaryProviders; diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java index 0f914c32346d..0187ce8140f5 100644 --- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java @@ -65,10 +65,13 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ IAutoFillManagerClient autoFillCallback) { super(context, sessionCallback, lock, userId, callingUid, request, callback, RequestInfo.TYPE_GET, callingAppInfo, enabledProviders, - cancellationSignal, 0L); + cancellationSignal, 0L, /*shouldBindClientToDeath=*/ false); mAutoFillCallback = autoFillCallback; mAutofillSessionId = request.getData().getInt(SESSION_ID_KEY, -1); mAutofillRequestId = request.getData().getInt(REQUEST_ID_KEY, -1); + if (mAutoFillCallback != null) { + setUpClientCallbackListener(mAutoFillCallback.asBinder()); + } } /** @@ -144,17 +147,27 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ @Override public void onFinalErrorReceived(ComponentName componentName, String errorType, String message) { - // Not applicable for session without UI + respondToClientWithErrorAndFinish(errorType, message); } @Override public void onUiCancellation(boolean isUserCancellation) { - // Not applicable for session without UI + String exception = GetCandidateCredentialsException.TYPE_USER_CANCELED; + String message = "User cancelled the selector"; + if (!isUserCancellation) { + exception = GetCandidateCredentialsException.TYPE_INTERRUPTED; + message = "The UI was interrupted - please try again."; + } + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, message); } @Override public void onUiSelectorInvocationFailure() { - // Not applicable for session without UI + String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL; + mRequestSessionMetric.collectFrameworkException(exception); + respondToClientWithErrorAndFinish(exception, + "No credentials available."); } @Override diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java index 3f57c804cba0..49ea19a6f098 100644 --- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java @@ -57,7 +57,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest, long startedTimestamp) { super(context, sessionCallback, lock, userId, callingUid, request, callback, getRequestInfoFromRequest(request), callingAppInfo, enabledProviders, - cancellationSignal, startedTimestamp); + cancellationSignal, startedTimestamp, /*shouldBindClientToDeath=*/ true); mRequestSessionMetric.collectGetFlowInitialMetricInfo(request); } diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java index da44aac5826a..67c52e6e4719 100644 --- a/services/credentials/java/com/android/server/credentials/RequestSession.java +++ b/services/credentials/java/com/android/server/credentials/RequestSession.java @@ -122,7 +122,8 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential @NonNull String requestType, CallingAppInfo callingAppInfo, Set<ComponentName> enabledProviders, - CancellationSignal cancellationSignal, long timestampStarted) { + CancellationSignal cancellationSignal, long timestampStarted, + boolean shouldBindClientToDeath) { mContext = context; mLock = lock; mSessionCallback = sessionCallback; @@ -146,16 +147,18 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted, mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType)); setCancellationListener(); - if (Flags.clearSessionEnabled()) { - setUpClientCallbackListener(); + if (shouldBindClientToDeath && Flags.clearSessionEnabled()) { + if (mClientCallback != null && mClientCallback instanceof IInterface) { + setUpClientCallbackListener(((IInterface) mClientCallback).asBinder()); + } } } - private void setUpClientCallbackListener() { + protected void setUpClientCallbackListener(IBinder clientBinder) { if (mClientCallback != null && mClientCallback instanceof IInterface) { IInterface callback = (IInterface) mClientCallback; try { - callback.asBinder().linkToDeath(mDeathRecipient, 0); + clientBinder.linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { Slog.e(TAG, e.getMessage()); } diff --git a/services/lint-baseline.xml b/services/lint-baseline.xml index 8489c17dd878..a311d07e52fb 100644 --- a/services/lint-baseline.xml +++ b/services/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="SimpleManualPermissionEnforcement" @@ -56,4 +56,4 @@ column="13"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/print/lint-baseline.xml b/services/print/lint-baseline.xml index 1bf031a9e289..11c0cc8ea93c 100644 --- a/services/print/lint-baseline.xml +++ b/services/print/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="SimpleManualPermissionEnforcement" @@ -12,4 +12,4 @@ column="13"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java deleted file mode 100644 index 4cc68cf11e69..000000000000 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.display; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; -import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; - -import static org.junit.Assert.assertNotNull; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.Mockito.atLeastOnce; -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 static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; - -import android.app.ActivityManager; -import android.content.Context; -import android.content.res.Resources; -import android.hardware.Sensor; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.hardware.display.BrightnessInfo; -import android.hardware.display.DisplayManagerInternal; -import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; -import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.PowerManager; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.test.TestLooper; -import android.platform.test.annotations.RequiresFlagsDisabled; -import android.platform.test.annotations.RequiresFlagsEnabled; -import android.platform.test.flag.junit.CheckFlagsRule; -import android.platform.test.flag.junit.DeviceFlagsValueProvider; -import android.provider.Settings; -import android.testing.TestableContext; -import android.util.FloatProperty; -import android.util.SparseArray; -import android.view.Display; -import android.view.DisplayInfo; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; - -import com.android.modules.utils.testing.ExtendedMockitoRule; -import com.android.server.LocalServices; -import com.android.server.am.BatteryStatsService; -import com.android.server.display.RampAnimator.DualRampAnimator; -import com.android.server.display.brightness.BrightnessEvent; -import com.android.server.display.brightness.clamper.BrightnessClamperController; -import com.android.server.display.brightness.clamper.HdrClamper; -import com.android.server.display.color.ColorDisplayService; -import com.android.server.display.config.SensorData; -import com.android.server.display.feature.DisplayManagerFlags; -import com.android.server.display.feature.flags.Flags; -import com.android.server.display.layout.Layout; -import com.android.server.display.whitebalance.DisplayWhiteBalanceController; -import com.android.server.policy.WindowManagerPolicy; -import com.android.server.testutils.OffsettableClock; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.quality.Strictness; -import org.mockito.stubbing.Answer; - -import java.util.List; - - -@SmallTest -@RunWith(AndroidJUnit4.class) -public final class DisplayPowerController2Test { - private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY; - private static final String UNIQUE_ID = "unique_id_test123"; - private static final int FOLLOWER_DISPLAY_ID = DISPLAY_ID + 1; - private static final String FOLLOWER_UNIQUE_ID = "unique_id_456"; - private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1; - private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; - private static final float PROX_SENSOR_MAX_RANGE = 5; - private static final float BRIGHTNESS_RAMP_RATE_MINIMUM = 0.0f; - private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f; - private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f; - private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f; - private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f; - private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f; - private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f; - - private static final long BRIGHTNESS_RAMP_INCREASE_MAX = 1000; - private static final long BRIGHTNESS_RAMP_DECREASE_MAX = 2000; - private static final long BRIGHTNESS_RAMP_INCREASE_MAX_IDLE = 3000; - private static final long BRIGHTNESS_RAMP_DECREASE_MAX_IDLE = 4000; - - private OffsettableClock mClock; - private TestLooper mTestLooper; - private Handler mHandler; - private DisplayPowerControllerHolder mHolder; - private Sensor mProxSensor; - - @Mock - private DisplayPowerCallbacks mDisplayPowerCallbacksMock; - @Mock - private SensorManager mSensorManagerMock; - @Mock - private DisplayBlanker mDisplayBlankerMock; - @Mock - private BrightnessTracker mBrightnessTrackerMock; - @Mock - private WindowManagerPolicy mWindowManagerPolicyMock; - @Mock - private PowerManager mPowerManagerMock; - @Mock - private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; - @Mock - private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; - @Mock - private DisplayManagerFlags mDisplayManagerFlagsMock; - @Mock - private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; - @Captor - private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; - - @Rule - public final TestableContext mContext = new TestableContext( - InstrumentationRegistry.getInstrumentation().getContext()); - - @Rule - public final ExtendedMockitoRule mExtendedMockitoRule = - new ExtendedMockitoRule.Builder(this) - .setStrictness(Strictness.LENIENT) - .spyStatic(SystemProperties.class) - .spyStatic(BatteryStatsService.class) - .spyStatic(ActivityManager.class) - .build(); - - @Rule - public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); - - @Before - public void setUp() throws Exception { - mClock = new OffsettableClock.Stopped(); - mTestLooper = new TestLooper(mClock::now); - mHandler = new Handler(mTestLooper.getLooper()); - - // Set some settings to minimize unexpected events and have a consistent starting state - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); - Settings.System.putFloatForUser(mContext.getContentResolver(), - Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0, UserHandle.USER_CURRENT); - - addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock); - addLocalServiceMock(ColorDisplayService.ColorDisplayServiceInternal.class, - mCdsiMock); - - mContext.addMockSystemService(PowerManager.class, mPowerManagerMock); - - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.bool.config_displayColorFadeDisabled, false); - - doAnswer((Answer<Void>) invocationOnMock -> null).when(() -> - SystemProperties.set(anyString(), any())); - doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); - doAnswer((Answer<Boolean>) invocationOnMock -> false) - .when(ActivityManager::isLowRamDeviceStatic); - - setUpSensors(); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - } - - @After - public void tearDown() { - LocalServices.removeServiceForTest(WindowManagerPolicy.class); - LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); - } - - @Test - public void testReleaseProxSuspendBlockersOnExit() throws Exception { - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState to start listener for the prox sensor - advanceTime(1); - - SensorEventListener listener = getSensorEventListener(mProxSensor); - assertNotNull(listener); - - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 5)); - advanceTime(1); - - // two times, one for unfinished business and one for proximity - verify(mHolder.wakelockController, times(2)).acquireWakelock( - WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); - verify(mHolder.wakelockController).acquireWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); - - mHolder.dpc.stop(); - advanceTime(1); - // two times, one for unfinished business and one for proximity - verify(mHolder.wakelockController, times(2)).acquireWakelock( - WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); - verify(mHolder.wakelockController).acquireWakelock( - WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); - } - - @Test - public void testScreenOffBecauseOfProximity() throws Exception { - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState to start listener for the prox sensor - advanceTime(1); - - SensorEventListener listener = getSensorEventListener(mProxSensor); - assertNotNull(listener); - - // Send a positive proximity event - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); - advanceTime(1); - - // The display should have been turned off - verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); - - clearInvocations(mHolder.displayPowerState); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); - // Send a negative proximity event - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, - (int) PROX_SENSOR_MAX_RANGE + 1)); - // Advance time by less than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY - advanceTime(1); - - // The prox sensor is debounced so the display should not have been turned back on yet - verify(mHolder.displayPowerState, never()).setScreenState(Display.STATE_ON); - - // Advance time by more than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY - advanceTime(1000); - - // The display should have been turned back on - verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); - } - - @Test - public void testScreenOffBecauseOfProximity_ProxSensorGone() throws Exception { - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState to start listener for the prox sensor - advanceTime(1); - - SensorEventListener listener = getSensorEventListener(mProxSensor); - assertNotNull(listener); - - // Send a positive proximity event - listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); - advanceTime(1); - - // The display should have been turned off - verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); - - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); - // The display device changes and we no longer have a prox sensor - reset(mSensorManagerMock); - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mock(DisplayDeviceConfig.class), /* isEnabled= */ true); - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); - - advanceTime(1); // Run updatePowerState - - // The display should have been turned back on and the listener should have been - // unregistered - verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); - verify(mSensorManagerMock).unregisterListener(listener); - } - - @Test - public void testProximitySensorListenerNotRegisteredForNonDefaultDisplay() { - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - // send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - final DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - followerDpc.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState - advanceTime(1); - - verify(mSensorManagerMock, never()).registerListener(any(SensorEventListener.class), - eq(mProxSensor), anyInt(), any(Handler.class)); - } - - @Test - public void testDisplayBrightnessFollowers_BothDpcsSupportNits() { - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - - // Test different float scale values - float leadBrightness = 0.3f; - float followerBrightness = 0.4f; - float nits = 300; - when(mHolder.automaticBrightnessController.convertToNits(leadBrightness)).thenReturn(nits); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(followerBrightness); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness); - listener.onBrightnessChanged(leadBrightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), anyFloat(), eq(false)); - verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(), - anyFloat(), eq(false)); - - clearInvocations(mHolder.animator, followerDpc.animator); - - // Test the same float scale value - float brightness = 0.6f; - nits = 600; - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() { - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - - float brightness = 0.3f; - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(300f); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat())) - .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() { - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - - float brightness = 0.3f; - when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() { - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - - float brightness = 0.3f; - when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat())) - .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowers_AutomaticBrightness() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - float leadBrightness = 0.1f; - float rawLeadBrightness = 0.3f; - float followerBrightness = 0.4f; - float nits = 300; - float ambientLux = 3000; - when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness()) - .thenReturn(rawLeadBrightness); - when(mHolder.automaticBrightnessController - .getAutomaticScreenBrightness(any(BrightnessEvent.class))) - .thenReturn(leadBrightness); - when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness)) - .thenReturn(nits); - when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(followerBrightness); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - // One triggered by handleBrightnessModeChange, another triggered by setBrightnessToFollow - verify(followerDpc.hbmController, times(2)).onAmbientLuxChange(ambientLux); - verify(followerDpc.animator, times(2)).animateTo(eq(followerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness); - when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness); - clearInvocations(mHolder.animator, followerDpc.animator); - - leadBrightness = 0.05f; - rawLeadBrightness = 0.2f; - followerBrightness = 0.3f; - nits = 200; - ambientLux = 2000; - when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness()) - .thenReturn(rawLeadBrightness); - when(mHolder.automaticBrightnessController - .getAutomaticScreenBrightness(any(BrightnessEvent.class))) - .thenReturn(leadBrightness); - when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness)) - .thenReturn(nits); - when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(followerBrightness); - - mHolder.dpc.updateBrightness(); - advanceTime(1); // Run updatePowerState - - // The second time, the animation rate should be slow - verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE), eq(false)); - verify(followerDpc.hbmController).onAmbientLuxChange(ambientLux); - verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowersRemoval_RemoveSingleFollower() { - DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, - FOLLOWER_UNIQUE_ID); - DisplayPowerControllerHolder secondFollowerDpc = createDisplayPowerController( - SECOND_FOLLOWER_DISPLAY_ID, SECOND_FOLLOWER_UNIQUE_DISPLAY_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(secondFollowerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - secondFollowerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - // Set the initial brightness on the DPC we're going to remove so we have a fixed value for - // it to return to. - listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(followerDpc.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener followerListener = listenerCaptor.getValue(); - final float initialFollowerBrightness = 0.3f; - when(followerDpc.brightnessSetting.getBrightness()).thenReturn(initialFollowerBrightness); - followerListener.onBrightnessChanged(initialFollowerBrightness); - advanceTime(1); - verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(followerDpc.displayPowerState.getScreenBrightness()) - .thenReturn(initialFollowerBrightness); - - mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); - mHolder.dpc.addDisplayBrightnessFollower(secondFollowerDpc.dpc); - clearInvocations(followerDpc.animator); - - // Validate both followers are correctly registered and receiving brightness updates - float brightness = 0.6f; - float nits = 600; - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); - when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness); - when(secondFollowerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness); - clearInvocations(mHolder.animator, followerDpc.animator, secondFollowerDpc.animator); - - // Remove the first follower and validate it goes back to its original brightness. - mHolder.dpc.removeDisplayBrightnessFollower(followerDpc.dpc); - advanceTime(1); - verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); - - when(followerDpc.displayPowerState.getScreenBrightness()) - .thenReturn(initialFollowerBrightness); - clearInvocations(followerDpc.animator); - - // Change the brightness of the lead display and validate only the second follower responds - brightness = 0.7f; - nits = 700; - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); - when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerDpc.animator, never()).animateTo(anyFloat(), anyFloat(), anyFloat(), - anyBoolean()); - verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testDisplayBrightnessFollowersRemoval_RemoveAllFollowers() { - DisplayPowerControllerHolder followerHolder = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - DisplayPowerControllerHolder secondFollowerHolder = - createDisplayPowerController(SECOND_FOLLOWER_DISPLAY_ID, - SECOND_FOLLOWER_UNIQUE_DISPLAY_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(followerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(secondFollowerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - followerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - secondFollowerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = - ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); - - // Set the initial brightness on the DPCs we're going to remove so we have a fixed value for - // it to return to. - listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(followerHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener followerListener = listenerCaptor.getValue(); - listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); - verify(secondFollowerHolder.brightnessSetting).registerListener(listenerCaptor.capture()); - BrightnessSetting.BrightnessSettingListener secondFollowerListener = - listenerCaptor.getValue(); - final float initialFollowerBrightness = 0.3f; - when(followerHolder.brightnessSetting.getBrightness()).thenReturn( - initialFollowerBrightness); - when(secondFollowerHolder.brightnessSetting.getBrightness()).thenReturn( - initialFollowerBrightness); - followerListener.onBrightnessChanged(initialFollowerBrightness); - secondFollowerListener.onBrightnessChanged(initialFollowerBrightness); - advanceTime(1); - verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(followerHolder.displayPowerState.getScreenBrightness()) - .thenReturn(initialFollowerBrightness); - when(secondFollowerHolder.displayPowerState.getScreenBrightness()) - .thenReturn(initialFollowerBrightness); - - mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc); - mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc); - clearInvocations(followerHolder.animator, secondFollowerHolder.animator); - - // Validate both followers are correctly registered and receiving brightness updates - float brightness = 0.6f; - float nits = 600; - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); - when(followerHolder.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(secondFollowerHolder.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(brightness); - when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); - listener.onBrightnessChanged(brightness); - advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); - when(followerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); - when(secondFollowerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); - clearInvocations(mHolder.animator, followerHolder.animator, secondFollowerHolder.animator); - - // Stop the lead DPC and validate that the followers go back to their original brightness. - mHolder.dpc.stop(); - advanceTime(1); - verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); - verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); - clearInvocations(followerHolder.animator, secondFollowerHolder.animator); - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) - public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - final float sdrBrightness = 0.1f; - final float hdrBrightness = 0.3f; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(sdrBrightness); - when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(1.0f); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(sdrBrightness); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); - - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); - clearInvocations(mHolder.animator); - - mHolder.dpc.updateBrightness(); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) - public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - final float sdrBrightness = 0.1f; - final float hdrBrightness = 0.3f; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(sdrBrightness); - when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(1.0f); - - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(hdrBrightness); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); - - clearInvocations(mHolder.animator); - - mHolder.dpc.updateBrightness(); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); - } - - @Test - public void testDoesNotSetScreenStateForNonDefaultDisplayUntilBootCompleted() { - // We should still set screen state for the default display - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt()); - - mHolder = createDisplayPowerController(42, UNIQUE_ID); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); - - mHolder.dpc.onBootCompleted(); - advanceTime(1); // Run updatePowerState - verify(mHolder.displayPowerState).setScreenState(anyInt()); - } - - @Test - public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_OFF; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(true); - - // The display turns on and we use the brightness value recommended by - // ScreenOffBrightnessSensorController - clearInvocations(mHolder.screenOffBrightnessSensorController); - float brightness = 0.14f; - when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) - .thenReturn(brightness); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .getAutomaticScreenBrightness(); - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat(), eq(false)); - } - - @Test - public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(true); - - // The display turns on and we use the brightness value recommended by - // ScreenOffBrightnessSensorController - clearInvocations(mHolder.screenOffBrightnessSensorController); - float brightness = 0.14f; - when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) - .thenReturn(brightness); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .getAutomaticScreenBrightness(); - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat(), eq(false)); - } - - @Test - public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { - // Tests are set up with manual brightness by default, so no need to set it here. - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_OFF; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(false); - } - - @Test - public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(false); - } - - @Test - public void testSetScreenOffBrightnessSensorDisabled_DisplayIsOn() { - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(false); - } - - @Test - public void testSetScreenOffBrightnessSensorDisabled_DisplayIsAFollower() { - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_OFF; - - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, /* leadDisplayId= */ 42); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) - .setLightSensorEnabled(false); - } - - @Test - public void testStopScreenOffBrightnessSensorControllerWhenDisplayDeviceChanges() { - // New display device - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mock(DisplayDeviceConfig.class), /* isEnabled= */ true); - - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.screenOffBrightnessSensorController).stop(); - } - - @Test - public void testAutoBrightnessEnabled_DisplayIsOn() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, - /* shouldResetShortTermModel= */ false - ); - verify(mHolder.hbmController) - .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); - } - - @Test - public void testAutoBrightnessEnabled_DisplayIsInDoze() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE, - /* shouldResetShortTermModel= */ false - ); - verify(mHolder.hbmController) - .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); - } - - @Test - public void testAutoBrightnessDisabled_ManualBrightnessMode() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - // One triggered by the test, the other by handleBrightnessModeChange - verify(mHolder.automaticBrightnessController, times(2)).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, - /* shouldResetShortTermModel= */ false - ); - verify(mHolder.hbmController, times(2)) - .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); - } - - @Test - public void testAutoBrightnessDisabled_DisplayIsOff() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_OFF; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_OFF, - /* shouldResetShortTermModel= */ false - ); - verify(mHolder.hbmController).setAutoBrightnessEnabled( - AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE); - } - - @Test - public void testAutoBrightnessDisabled_DisplayIsInDoze() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE, - /* shouldResetShortTermModel= */ false - ); - verify(mHolder.hbmController).setAutoBrightnessEnabled( - AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE); - } - - @Test - public void testAutoBrightnessDisabled_FollowerDisplay() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mHolder.dpc.setBrightnessToFollow(0.3f, -1, 0, /* slowChange= */ false); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - // One triggered by the test, the other by handleBrightnessModeChange - verify(mHolder.automaticBrightnessController, times(2)).configure( - AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, - /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, - /* userChangedBrightness= */ false, /* adjustment= */ 0, - /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, - /* shouldResetShortTermModel= */ false - ); - - // HBM should be allowed for the follower display - verify(mHolder.hbmController) - .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); - } - - @Test - public void testBrightnessNitsPersistWhenDisplayDeviceChanges() { - float brightness = 0.3f; - float nits = 500; - mContext.getOrCreateTestableResources().addOverride( - com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay, - true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); - - mHolder.dpc.setBrightness(brightness); - verify(mHolder.brightnessSetting).setBrightnessNitsForDefaultDisplay(nits); - - float newBrightness = 0.4f; - when(mHolder.brightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits); - when(mHolder.automaticBrightnessController.getBrightnessFromNits(nits)) - .thenReturn(newBrightness); - // New display device - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mock(DisplayDeviceConfig.class), /* isEnabled= */ true); - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - // One triggered by handleBrightnessModeChange, another triggered by onDisplayChanged - verify(mHolder.animator, times(2)).animateTo(eq(newBrightness), anyFloat(), anyFloat(), - eq(false)); - } - - @Test - public void testShortTermModelPersistsWhenDisplayDeviceChanges() { - float lux = 2000; - float nits = 500; - when(mHolder.automaticBrightnessController.getUserLux()).thenReturn(lux); - when(mHolder.automaticBrightnessController.getUserNits()).thenReturn(nits); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); - clearInvocations(mHolder.injector); - - // New display device - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mock(DisplayDeviceConfig.class), /* isEnabled= */ true); - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); - advanceTime(1); - - verify(mHolder.injector).getAutomaticBrightnessController( - any(AutomaticBrightnessController.Callbacks.class), - any(Looper.class), - eq(mSensorManagerMock), - /* lightSensor= */ any(), - /* brightnessMappingStrategyMap= */ any(SparseArray.class), - /* lightSensorWarmUpTime= */ anyInt(), - /* brightnessMin= */ anyFloat(), - /* brightnessMax= */ anyFloat(), - /* dozeScaleFactor */ anyFloat(), - /* lightSensorRate= */ anyInt(), - /* initialLightSensorRate= */ anyInt(), - /* brighteningLightDebounceConfig */ anyLong(), - /* darkeningLightDebounceConfig */ anyLong(), - /* brighteningLightDebounceConfigIdle= */ anyLong(), - /* darkeningLightDebounceConfigIdle= */ anyLong(), - /* resetAmbientLuxAfterWarmUpConfig= */ anyBoolean(), - any(HysteresisLevels.class), - any(HysteresisLevels.class), - any(HysteresisLevels.class), - any(HysteresisLevels.class), - eq(mContext), - any(BrightnessRangeController.class), - any(BrightnessThrottler.class), - /* ambientLightHorizonShort= */ anyInt(), - /* ambientLightHorizonLong= */ anyInt(), - eq(lux), - eq(nits) - ); - } - - @Test - public void testUpdateBrightnessThrottlingDataId() { - mHolder.display.getDisplayInfoLocked().thermalBrightnessThrottlingDataId = - "throttling-data-id"; - clearInvocations(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()); - - mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()) - .getThermalBrightnessThrottlingDataMapByThrottlingId(); - } - - @Test - public void testSetBrightness_BrightnessShouldBeClamped() { - float clampedBrightness = 0.6f; - when(mHolder.hbmController.getCurrentBrightnessMax()).thenReturn(clampedBrightness); - - mHolder.dpc.setBrightness(PowerManager.BRIGHTNESS_MAX); - - verify(mHolder.brightnessSetting).setBrightness(clampedBrightness); - } - - @Test - public void testDwbcCallsHappenOnHandler() { - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - - mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true); - - // dispatch handler looper - advanceTime(1); - verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true); - } - - @Test - public void testRampRatesIdle() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - float brightness = 0.6f; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(brightness); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); - brightness = 0.05f; - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(brightness); - - mHolder.dpc.updateBrightness(); - advanceTime(1); // Run updatePowerState - - // The second time, the animation rate should be slow - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE), eq(false)); - - brightness = 0.9f; - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(brightness); - - mHolder.dpc.updateBrightness(); - advanceTime(1); // Run updatePowerState - // The third time, the animation rate should be slow - verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE), eq(false)); - } - - @Test - public void testRampRateForHdrContent_HdrClamperOff() { - float hdrBrightness = 0.8f; - float clampedBrightness = 0.6f; - float transitionRate = 1.5f; - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); - when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness); - when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator, atLeastOnce()).animateTo(eq(hdrBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testRampRateForHdrContent_HdrClamperOn() { - float clampedBrightness = 0.6f; - float transitionRate = 1.5f; - when(mDisplayManagerFlagsMock.isHdrClamperEnabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(PowerManager.BRIGHTNESS_MAX); - when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness); - when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator, atLeastOnce()).animateTo(eq(clampedBrightness), anyFloat(), - eq(transitionRate), eq(true)); - } - - @Test - public void testRampRateForClampersControllerApplied() { - float transitionRate = 1.5f; - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); - when(mHolder.clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( - invocation -> DisplayBrightnessState.builder() - .setIsSlowChange(invocation.getArgument(2)) - .setBrightness(invocation.getArgument(1)) - .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) - .setCustomAnimationRate(transitionRate).build()); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator, atLeastOnce()).animateTo(anyFloat(), anyFloat(), - eq(transitionRate), anyBoolean()); - } - - @Test - public void testRampRateForClampersControllerNotApplied_ifDoze() { - float transitionRate = 1.5f; - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - dpr.dozeScreenState = Display.STATE_UNKNOWN; - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); - when(mHolder.clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( - invocation -> DisplayBrightnessState.builder() - .setIsSlowChange(invocation.getArgument(2)) - .setBrightness(invocation.getArgument(1)) - .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) - .setCustomAnimationRate(transitionRate).build()); - - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.animator, atLeastOnce()).animateTo(anyFloat(), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), anyBoolean()); - verify(mHolder.animator, never()).animateTo(anyFloat(), anyFloat(), - eq(transitionRate), anyBoolean()); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) - public void testRampMaxTimeInteractiveThenIdle() { - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState - advanceTime(1); - - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mHolder.config, /* isEnabled= */ true); - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, - BRIGHTNESS_RAMP_DECREASE_MAX); - - // switch to idle mode - mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - advanceTime(1); - - // A second time, when switching to idle mode. - verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, - BRIGHTNESS_RAMP_DECREASE_MAX); - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) - public void testRampMaxTimeInteractiveThenIdle_DifferentValues() { - when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); - - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState - advanceTime(1); - - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mHolder.config, /* isEnabled= */ true); - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, - BRIGHTNESS_RAMP_DECREASE_MAX); - - // switch to idle mode - mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - advanceTime(1); - - // A second time, when switching to idle mode. - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, - BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); - } - - @Test - @RequiresFlagsDisabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) - public void testRampMaxTimeIdle() { - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - // Run updatePowerState - advanceTime(1); - // Once on setup - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, - BRIGHTNESS_RAMP_DECREASE_MAX); - - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mHolder.config, /* isEnabled= */ true); - - // switch to idle mode - mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - - // A second time when switching to idle mode. - verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, - BRIGHTNESS_RAMP_DECREASE_MAX); - } - - @Test - @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) - public void testRampMaxTimeIdle_DifferentValues() { - when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); - - // Send a display power request - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - dpr.useProximitySensor = true; - mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - - // Run updatePowerState - advanceTime(1); - - setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), - mHolder.config, /* isEnabled= */ true); - - // switch to idle mode - mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, - BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); - } - - @Test - public void testDozeScreenStateOverride_toSupportedOffloadStateFromDoze_DisplayStateChanges() { - // set up. - int initState = Display.STATE_DOZE; - int supportedTargetState = Display.STATE_DOZE_SUSPEND; - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - doAnswer(invocation -> { - when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); - return null; - }).when(mHolder.displayPowerState).setScreenState(anyInt()); - mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); - - // start with DOZE. - when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - mHolder.dpc.overrideDozeScreenState(supportedTargetState); - advanceTime(1); // Run updatePowerState - - verify(mHolder.displayPowerState).setScreenState(supportedTargetState); - } - - @Test - public void testDozeScreenStateOverride_toUnSupportedOffloadStateFromDoze_stateRemains() { - // set up. - int initState = Display.STATE_DOZE; - int unSupportedTargetState = Display.STATE_ON; - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - doAnswer(invocation -> { - when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); - return null; - }).when(mHolder.displayPowerState).setScreenState(anyInt()); - mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); - - // start with DOZE. - when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - mHolder.dpc.overrideDozeScreenState(unSupportedTargetState); - advanceTime(1); // Run updatePowerState - - verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); - } - - @Test - public void testDozeScreenStateOverride_toSupportedOffloadStateFromOFF_stateRemains() { - // set up. - int initState = Display.STATE_OFF; - int supportedTargetState = Display.STATE_DOZE_SUSPEND; - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - doAnswer(invocation -> { - when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); - return null; - }).when(mHolder.displayPowerState).setScreenState(anyInt()); - mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); - - // start with OFF. - when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_OFF; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - mHolder.dpc.overrideDozeScreenState(supportedTargetState); - advanceTime(1); // Run updatePowerState - - verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); - } - - @Test - public void testBrightnessFromOffload() { - when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - float brightness = 0.34f; - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); - mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); - - mHolder.dpc.setBrightnessFromOffload(brightness); - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - // One triggered by handleBrightnessModeChange, another triggered by - // setBrightnessFromOffload - verify(mHolder.animator, times(2)).animateTo(eq(brightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - } - - @Test - public void testSwitchToDozeAutoBrightnessMode() { - when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - dpr.policy = DisplayPowerRequest.POLICY_DOZE; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - // One triggered by handleBrightnessModeChange, another triggered by requestPowerState - verify(mHolder.automaticBrightnessController, times(2)) - .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); - - // Back to default mode - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController).switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT); - } - - @Test - public void testDoesNotSwitchFromIdleToDozeAutoBrightnessMode() { - when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController, never()) - .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); - } - - @Test - public void testDoesNotSwitchDozeAutoBrightnessModeIfFeatureFlagOff() { - when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(false); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); - mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); - advanceTime(1); // Run updatePowerState - - verify(mHolder.automaticBrightnessController, never()) - .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); - } - - /** - * Creates a mock and registers it to {@link LocalServices}. - */ - private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { - LocalServices.removeServiceForTest(clazz); - LocalServices.addService(clazz, mock); - } - - private void advanceTime(long timeMs) { - mClock.fastForward(timeMs); - mTestLooper.dispatchAll(); - } - - private void setUpSensors() throws Exception { - mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY, - PROX_SENSOR_MAX_RANGE); - Sensor screenOffBrightnessSensor = TestUtils.createSensor( - Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); - when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) - .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor)); - } - - private SensorEventListener getSensorEventListener(Sensor sensor) { - verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(), - eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class)); - return mSensorEventListenerCaptor.getValue(); - } - - private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock, - DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock, - boolean isEnabled) { - DisplayInfo info = new DisplayInfo(); - DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); - deviceInfo.uniqueId = uniqueId; - - when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId); - when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock); - when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); - when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); - when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); - when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); - when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); - when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock); - when(displayDeviceConfigMock.getProximitySensor()).thenReturn( - new SensorData(Sensor.STRING_TYPE_PROXIMITY, null)); - when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500}); - when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true); - when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn( - new SensorData()); - when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn( - new SensorData(Sensor.STRING_TYPE_LIGHT, null)); - when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux()) - .thenReturn(new int[0]); - - when(displayDeviceConfigMock.getBrightnessRampFastDecrease()) - .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_DECREASE); - when(displayDeviceConfigMock.getBrightnessRampFastIncrease()) - .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_INCREASE); - when(displayDeviceConfigMock.getBrightnessRampSlowDecrease()) - .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE); - when(displayDeviceConfigMock.getBrightnessRampSlowIncrease()) - .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE); - when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle()) - .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE); - when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle()) - .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE); - - when(displayDeviceConfigMock.getBrightnessRampIncreaseMaxMillis()) - .thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX); - when(displayDeviceConfigMock.getBrightnessRampDecreaseMaxMillis()) - .thenReturn(BRIGHTNESS_RAMP_DECREASE_MAX); - when(displayDeviceConfigMock.getBrightnessRampIncreaseMaxIdleMillis()) - .thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE); - when(displayDeviceConfigMock.getBrightnessRampDecreaseMaxIdleMillis()) - .thenReturn(BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); - } - - private DisplayPowerControllerHolder createDisplayPowerController(int displayId, - String uniqueId) { - return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true); - } - - private DisplayPowerControllerHolder createDisplayPowerController(int displayId, - String uniqueId, boolean isEnabled) { - final DisplayPowerState displayPowerState = mock(DisplayPowerState.class); - final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class); - final AutomaticBrightnessController automaticBrightnessController = - mock(AutomaticBrightnessController.class); - final WakelockController wakelockController = mock(WakelockController.class); - final BrightnessMappingStrategy brightnessMappingStrategy = - mock(BrightnessMappingStrategy.class); - final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class); - final ScreenOffBrightnessSensorController screenOffBrightnessSensorController = - mock(ScreenOffBrightnessSensorController.class); - final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class); - final HdrClamper hdrClamper = mock(HdrClamper.class); - BrightnessClamperController clamperController = mock(BrightnessClamperController.class); - - when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX); - when(clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( - invocation -> DisplayBrightnessState.builder() - .setIsSlowChange(invocation.getArgument(2)) - .setBrightness(invocation.getArgument(1)) - .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) - .setCustomAnimationRate(-1).build()); - - TestInjector injector = spy(new TestInjector(displayPowerState, animator, - automaticBrightnessController, wakelockController, brightnessMappingStrategy, - hysteresisLevels, screenOffBrightnessSensorController, hbmController, hdrClamper, - clamperController, mDisplayManagerFlagsMock)); - - final LogicalDisplay display = mock(LogicalDisplay.class); - final DisplayDevice device = mock(DisplayDevice.class); - final HighBrightnessModeMetadata hbmMetadata = mock(HighBrightnessModeMetadata.class); - final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class); - final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class); - - setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); - - final DisplayPowerController2 dpc = new DisplayPowerController2( - mContext, injector, mDisplayPowerCallbacksMock, mHandler, - mSensorManagerMock, mDisplayBlankerMock, display, - mBrightnessTrackerMock, brightnessSetting, () -> { - }, - hbmMetadata, /* bootCompleted= */ false, mDisplayManagerFlagsMock); - - return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting, - animator, automaticBrightnessController, wakelockController, - screenOffBrightnessSensorController, hbmController, hdrClamper, clamperController, - hbmMetadata, brightnessMappingStrategy, injector, config); - } - - /** - * A class for holding a DisplayPowerController under test and all the mocks specifically - * related to it. - */ - private static class DisplayPowerControllerHolder { - public final DisplayPowerController2 dpc; - public final LogicalDisplay display; - public final DisplayPowerState displayPowerState; - public final BrightnessSetting brightnessSetting; - public final DualRampAnimator<DisplayPowerState> animator; - public final AutomaticBrightnessController automaticBrightnessController; - public final WakelockController wakelockController; - public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController; - public final HighBrightnessModeController hbmController; - - public final HdrClamper hdrClamper; - public final BrightnessClamperController clamperController; - public final HighBrightnessModeMetadata hbmMetadata; - public final BrightnessMappingStrategy brightnessMappingStrategy; - public final DisplayPowerController2.Injector injector; - public final DisplayDeviceConfig config; - - DisplayPowerControllerHolder(DisplayPowerController2 dpc, LogicalDisplay display, - DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting, - DualRampAnimator<DisplayPowerState> animator, - AutomaticBrightnessController automaticBrightnessController, - WakelockController wakelockController, - ScreenOffBrightnessSensorController screenOffBrightnessSensorController, - HighBrightnessModeController hbmController, - HdrClamper hdrClamper, - BrightnessClamperController clamperController, - HighBrightnessModeMetadata hbmMetadata, - BrightnessMappingStrategy brightnessMappingStrategy, - DisplayPowerController2.Injector injector, - DisplayDeviceConfig config) { - this.dpc = dpc; - this.display = display; - this.displayPowerState = displayPowerState; - this.brightnessSetting = brightnessSetting; - this.animator = animator; - this.automaticBrightnessController = automaticBrightnessController; - this.wakelockController = wakelockController; - this.screenOffBrightnessSensorController = screenOffBrightnessSensorController; - this.hbmController = hbmController; - this.hdrClamper = hdrClamper; - this.clamperController = clamperController; - this.hbmMetadata = hbmMetadata; - this.brightnessMappingStrategy = brightnessMappingStrategy; - this.injector = injector; - this.config = config; - } - } - - private class TestInjector extends DisplayPowerController2.Injector { - private final DisplayPowerState mDisplayPowerState; - private final DualRampAnimator<DisplayPowerState> mAnimator; - private final AutomaticBrightnessController mAutomaticBrightnessController; - private final WakelockController mWakelockController; - private final BrightnessMappingStrategy mBrightnessMappingStrategy; - private final HysteresisLevels mHysteresisLevels; - private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; - private final HighBrightnessModeController mHighBrightnessModeController; - - private final HdrClamper mHdrClamper; - - private final BrightnessClamperController mClamperController; - - private final DisplayManagerFlags mFlags; - - TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator, - AutomaticBrightnessController automaticBrightnessController, - WakelockController wakelockController, - BrightnessMappingStrategy brightnessMappingStrategy, - HysteresisLevels hysteresisLevels, - ScreenOffBrightnessSensorController screenOffBrightnessSensorController, - HighBrightnessModeController highBrightnessModeController, - HdrClamper hdrClamper, - BrightnessClamperController clamperController, - DisplayManagerFlags flags) { - mDisplayPowerState = dps; - mAnimator = animator; - mAutomaticBrightnessController = automaticBrightnessController; - mWakelockController = wakelockController; - mBrightnessMappingStrategy = brightnessMappingStrategy; - mHysteresisLevels = hysteresisLevels; - mScreenOffBrightnessSensorController = screenOffBrightnessSensorController; - mHighBrightnessModeController = highBrightnessModeController; - mHdrClamper = hdrClamper; - mClamperController = clamperController; - mFlags = flags; - } - - @Override - DisplayPowerController2.Clock getClock() { - return mClock::now; - } - - @Override - DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, - int displayId, int displayState) { - return mDisplayPowerState; - } - - @Override - DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps, - FloatProperty<DisplayPowerState> firstProperty, - FloatProperty<DisplayPowerState> secondProperty) { - return mAnimator; - } - - @Override - WakelockController getWakelockController(int displayId, - DisplayPowerCallbacks displayPowerCallbacks) { - return mWakelockController; - } - - @Override - DisplayPowerProximityStateController getDisplayPowerProximityStateController( - WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, - Looper looper, Runnable nudgeUpdatePowerState, int displayId, - SensorManager sensorManager) { - return new DisplayPowerProximityStateController(wakelockController, - displayDeviceConfig, looper, nudgeUpdatePowerState, displayId, - sensorManager, - new DisplayPowerProximityStateController.Injector() { - @Override - DisplayPowerProximityStateController.Clock createClock() { - return mClock::now; - } - }); - } - - @Override - AutomaticBrightnessController getAutomaticBrightnessController( - AutomaticBrightnessController.Callbacks callbacks, Looper looper, - SensorManager sensorManager, Sensor lightSensor, - SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap, - int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, - float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, - long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, - long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, - boolean resetAmbientLuxAfterWarmUpConfig, - HysteresisLevels ambientBrightnessThresholds, - HysteresisLevels screenBrightnessThresholds, - HysteresisLevels ambientBrightnessThresholdsIdle, - HysteresisLevels screenBrightnessThresholdsIdle, Context context, - BrightnessRangeController brightnessRangeController, - BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort, - int ambientLightHorizonLong, float userLux, float userNits) { - return mAutomaticBrightnessController; - } - - @Override - BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context, - DisplayDeviceConfig displayDeviceConfig, - DisplayWhiteBalanceController displayWhiteBalanceController) { - return mBrightnessMappingStrategy; - } - - @Override - HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, - float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, - float[] darkeningThresholdLevels, float minDarkeningThreshold, - float minBrighteningThreshold) { - return mHysteresisLevels; - } - - @Override - HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, - float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, - float[] darkeningThresholdLevels, float minDarkeningThreshold, - float minBrighteningThreshold, boolean potentialOldBrightnessRange) { - return mHysteresisLevels; - } - - @Override - ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( - SensorManager sensorManager, Sensor lightSensor, Handler handler, - ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, - BrightnessMappingStrategy brightnessMapper) { - return mScreenOffBrightnessSensorController; - } - - @Override - HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width, - int height, IBinder displayToken, String displayUniqueId, float brightnessMin, - float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData, - HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg, - Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, - Context context) { - return mHighBrightnessModeController; - } - - @Override - BrightnessRangeController getBrightnessRangeController( - HighBrightnessModeController hbmController, Runnable modeChangeCallback, - DisplayDeviceConfig displayDeviceConfig, Handler handler, - DisplayManagerFlags flags, IBinder displayToken, DisplayDeviceInfo info) { - return new BrightnessRangeController(hbmController, modeChangeCallback, - displayDeviceConfig, mHdrClamper, mFlags, displayToken, info); - } - - @Override - BrightnessClamperController getBrightnessClamperController(Handler handler, - BrightnessClamperController.ClamperChangeListener clamperChangeListener, - BrightnessClamperController.DisplayDeviceData data, Context context, - DisplayManagerFlags flags) { - return mClamperController; - } - - @Override - DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, - SensorManager sensorManager, Resources resources) { - return mDisplayWhiteBalanceControllerMock; - } - } -} diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index 943862f918bc..88a9758991f4 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -18,6 +18,8 @@ package com.android.server.display; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; import static org.junit.Assert.assertNotNull; @@ -67,15 +69,16 @@ import android.view.Display; import android.view.DisplayInfo; import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.internal.util.test.LocalServiceKeeperRule; import com.android.modules.utils.testing.ExtendedMockitoRule; +import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; import com.android.server.display.brightness.BrightnessEvent; +import com.android.server.display.brightness.clamper.BrightnessClamperController; +import com.android.server.display.brightness.clamper.HdrClamper; import com.android.server.display.color.ColorDisplayService; import com.android.server.display.config.SensorData; import com.android.server.display.feature.DisplayManagerFlags; @@ -85,6 +88,7 @@ import com.android.server.display.whitebalance.DisplayWhiteBalanceController; import com.android.server.policy.WindowManagerPolicy; import com.android.server.testutils.OffsettableClock; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -147,7 +151,6 @@ public final class DisplayPowerControllerTest { private DisplayManagerFlags mDisplayManagerFlagsMock; @Mock private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; - @Captor private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; @@ -165,9 +168,6 @@ public final class DisplayPowerControllerTest { .build(); @Rule - public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); - - @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); @Before @@ -183,10 +183,9 @@ public final class DisplayPowerControllerTest { Settings.System.putFloatForUser(mContext.getContentResolver(), Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0, UserHandle.USER_CURRENT); - mLocalServiceKeeperRule.overrideLocalService( - WindowManagerPolicy.class, mWindowManagerPolicyMock); - mLocalServiceKeeperRule.overrideLocalService( - ColorDisplayService.ColorDisplayServiceInternal.class, mCdsiMock); + addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock); + addLocalServiceMock(ColorDisplayService.ColorDisplayServiceInternal.class, + mCdsiMock); mContext.addMockSystemService(PowerManager.class, mPowerManagerMock); @@ -203,6 +202,12 @@ public final class DisplayPowerControllerTest { mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); } + @After + public void tearDown() { + LocalServices.removeServiceForTest(WindowManagerPolicy.class); + LocalServices.removeServiceForTest(ColorDisplayService.ColorDisplayServiceInternal.class); + } + @Test public void testReleaseProxSuspendBlockersOnExit() throws Exception { when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); @@ -222,19 +227,18 @@ public final class DisplayPowerControllerTest { advanceTime(1); // two times, one for unfinished business and one for proximity - verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker( - mHolder.dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID)); - verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker( - mHolder.dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID)); + verify(mHolder.wakelockController, times(2)).acquireWakelock( + WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); + verify(mHolder.wakelockController).acquireWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); mHolder.dpc.stop(); advanceTime(1); - // two times, one for unfinished business and one for proximity - verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker( - mHolder.dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID)); - verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker( - mHolder.dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID)); + verify(mHolder.wakelockController, times(2)).acquireWakelock( + WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); + verify(mHolder.wakelockController).acquireWakelock( + WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); } @Test @@ -316,14 +320,13 @@ public final class DisplayPowerControllerTest { @Test public void testProximitySensorListenerNotRegisteredForNonDefaultDisplay() { - DisplayPowerControllerHolder followerDpc = - createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); // send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; dpr.useProximitySensor = true; + final DisplayPowerControllerHolder followerDpc = + createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); followerDpc.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); // Run updatePowerState @@ -334,7 +337,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowers_BothDpcsSupportNits() { DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -363,13 +365,10 @@ public final class DisplayPowerControllerTest { when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness); listener.onBrightnessChanged(leadBrightness); advanceTime(1); // Send messages, run updatePowerState - verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), anyFloat(), eq(false)); verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + anyFloat(), eq(false)); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness); - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness); clearInvocations(mHolder.animator, followerDpc.animator); // Test the same float scale value @@ -388,7 +387,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() { DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -421,7 +419,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() { DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -452,7 +449,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() { DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -485,7 +481,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowers_AutomaticBrightness() { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, @@ -557,7 +552,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowersRemoval_RemoveSingleFollower() { DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -650,7 +644,6 @@ public final class DisplayPowerControllerTest { } @Test - @FlakyTest(bugId = 294107062) public void testDisplayBrightnessFollowersRemoval_RemoveAllFollowers() { DisplayPowerControllerHolder followerHolder = createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); @@ -737,6 +730,82 @@ public final class DisplayPowerControllerTest { } @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) + public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + final float sdrBrightness = 0.1f; + final float hdrBrightness = 0.3f; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(sdrBrightness); + when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(1.0f); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), + eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(sdrBrightness); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); + + when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); + when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); + clearInvocations(mHolder.animator); + + mHolder.dpc.updateBrightness(); + advanceTime(1); // Run updatePowerState + + verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), + eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) + public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + final float sdrBrightness = 0.1f; + final float hdrBrightness = 0.3f; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(sdrBrightness); + when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(1.0f); + + when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); + when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), + eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(hdrBrightness); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); + when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( + BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); + + clearInvocations(mHolder.animator); + + mHolder.dpc.updateBrightness(); + advanceTime(1); // Run updatePowerState + + verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), + eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); + } + + @Test public void testDoesNotSetScreenStateForNonDefaultDisplayUntilBootCompleted() { // We should still set screen state for the default display DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -761,6 +830,8 @@ public final class DisplayPowerControllerTest { Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); + DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_OFF; mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); @@ -798,6 +869,7 @@ public final class DisplayPowerControllerTest { Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_DOZE; mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); @@ -842,7 +914,6 @@ public final class DisplayPowerControllerTest { Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -1048,7 +1119,6 @@ public final class DisplayPowerControllerTest { mContext.getOrCreateTestableResources().addOverride( com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay, true); - mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); @@ -1199,76 +1269,98 @@ public final class DisplayPowerControllerTest { } @Test - @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) - public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - final float sdrBrightness = 0.1f; - final float hdrBrightness = 0.3f; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); - when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(sdrBrightness); + public void testRampRateForHdrContent_HdrClamperOff() { + float hdrBrightness = 0.8f; + float clampedBrightness = 0.6f; + float transitionRate = 1.5f; DisplayPowerRequest dpr = new DisplayPowerRequest(); + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); + when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( + BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); + when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); + when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness); + when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState - verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), + verify(mHolder.animator, atLeastOnce()).animateTo(eq(hdrBrightness), anyFloat(), eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + } - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(sdrBrightness); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); + @Test + public void testRampRateForHdrContent_HdrClamperOn() { + float clampedBrightness = 0.6f; + float transitionRate = 1.5f; + when(mDisplayManagerFlagsMock.isHdrClamperEnabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); + DisplayPowerRequest dpr = new DisplayPowerRequest(); + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); - clearInvocations(mHolder.animator); + when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(PowerManager.BRIGHTNESS_MAX); + when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness); + when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate); - mHolder.dpc.updateBrightness(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState - verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); + verify(mHolder.animator, atLeastOnce()).animateTo(eq(clampedBrightness), anyFloat(), + eq(transitionRate), eq(true)); } @Test - @RequiresFlagsEnabled(Flags.FLAG_FAST_HDR_TRANSITIONS) - public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { - Settings.System.putInt(mContext.getContentResolver(), - Settings.System.SCREEN_BRIGHTNESS_MODE, - Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); - final float sdrBrightness = 0.1f; - final float hdrBrightness = 0.3f; - when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + public void testRampRateForClampersControllerApplied() { + float transitionRate = 1.5f; + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + DisplayPowerRequest dpr = new DisplayPowerRequest(); when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); - when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( - any(BrightnessEvent.class))).thenReturn(sdrBrightness); + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); + when(mHolder.clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( + invocation -> DisplayBrightnessState.builder() + .setIsSlowChange(invocation.getArgument(2)) + .setBrightness(invocation.getArgument(1)) + .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) + .setCustomAnimationRate(transitionRate).build()); - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); - when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); - - DisplayPowerRequest dpr = new DisplayPowerRequest(); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState - verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); - - when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(hdrBrightness); - when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); - when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( - BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); + verify(mHolder.animator, atLeastOnce()).animateTo(anyFloat(), anyFloat(), + eq(transitionRate), anyBoolean()); + } - clearInvocations(mHolder.animator); + @Test + public void testRampRateForClampersControllerNotApplied_ifDoze() { + float transitionRate = 1.5f; + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_DOZE; + dpr.dozeScreenState = Display.STATE_UNKNOWN; + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f); + when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f); + when(mHolder.clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( + invocation -> DisplayBrightnessState.builder() + .setIsSlowChange(invocation.getArgument(2)) + .setBrightness(invocation.getArgument(1)) + .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) + .setCustomAnimationRate(transitionRate).build()); - mHolder.dpc.updateBrightness(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); // Run updatePowerState - verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), - eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); + verify(mHolder.animator, atLeastOnce()).animateTo(anyFloat(), anyFloat(), + eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), anyBoolean()); + verify(mHolder.animator, never()).animateTo(anyFloat(), anyFloat(), + eq(transitionRate), anyBoolean()); } @Test @@ -1285,14 +1377,14 @@ public final class DisplayPowerControllerTest { setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), mHolder.config, /* isEnabled= */ true); - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); - // switch to idle + // switch to idle mode mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); advanceTime(1); + // A second time, when switching to idle mode. verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); } @@ -1301,6 +1393,8 @@ public final class DisplayPowerControllerTest { @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) public void testRampMaxTimeInteractiveThenIdle_DifferentValues() { when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); + // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; @@ -1312,14 +1406,14 @@ public final class DisplayPowerControllerTest { setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), mHolder.config, /* isEnabled= */ true); - verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); - // switch to idle + // switch to idle mode mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); advanceTime(1); + // A second time, when switching to idle mode. verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); } @@ -1332,11 +1426,9 @@ public final class DisplayPowerControllerTest { dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; dpr.useProximitySensor = true; mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); - // Run updatePowerState advanceTime(1); - - // once on setup + // Once on setup verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); @@ -1346,7 +1438,7 @@ public final class DisplayPowerControllerTest { // switch to idle mode mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); - // second time when switching to idle screen brightness mode + // A second time when switching to idle mode. verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, BRIGHTNESS_RAMP_DECREASE_MAX); } @@ -1355,6 +1447,7 @@ public final class DisplayPowerControllerTest { @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) public void testRampMaxTimeIdle_DifferentValues() { when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true); // Send a display power request DisplayPowerRequest dpr = new DisplayPowerRequest(); @@ -1374,6 +1467,7 @@ public final class DisplayPowerControllerTest { verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); } + @Test public void testDozeScreenStateOverride_toSupportedOffloadStateFromDoze_DisplayStateChanges() { // set up. @@ -1451,6 +1545,89 @@ public final class DisplayPowerControllerTest { verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); } + @Test + public void testBrightnessFromOffload() { + when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + float brightness = 0.34f; + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); + + mHolder.dpc.setBrightnessFromOffload(brightness); + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + // One triggered by handleBrightnessModeChange, another triggered by + // setBrightnessFromOffload + verify(mHolder.animator, times(2)).animateTo(eq(brightness), anyFloat(), + eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); + } + + @Test + public void testSwitchToDozeAutoBrightnessMode() { + when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_DOZE; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + // One triggered by handleBrightnessModeChange, another triggered by requestPowerState + verify(mHolder.automaticBrightnessController, times(2)) + .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); + + // Back to default mode + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.automaticBrightnessController).switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT); + } + + @Test + public void testDoesNotSwitchFromIdleToDozeAutoBrightnessMode() { + when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); + when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.automaticBrightnessController, never()) + .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); + } + + @Test + public void testDoesNotSwitchDozeAutoBrightnessModeIfFeatureFlagOff() { + when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(false); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.automaticBrightnessController, never()) + .switchMode(AUTO_BRIGHTNESS_MODE_DOZE); + } + + /** + * Creates a mock and registers it to {@link LocalServices}. + */ + private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { + LocalServices.removeServiceForTest(clazz); + LocalServices.addService(clazz, mock); + } + private void advanceTime(long timeMs) { mClock.fastForward(timeMs); mTestLooper.dispatchAll(); @@ -1505,10 +1682,10 @@ public final class DisplayPowerControllerTest { .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE); when(displayDeviceConfigMock.getBrightnessRampSlowIncrease()) .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE); - when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle()) - .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE); when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle()) .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE); + when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle()) + .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE); when(displayDeviceConfigMock.getBrightnessRampIncreaseMaxMillis()) .thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX); @@ -1531,18 +1708,28 @@ public final class DisplayPowerControllerTest { final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class); final AutomaticBrightnessController automaticBrightnessController = mock(AutomaticBrightnessController.class); + final WakelockController wakelockController = mock(WakelockController.class); final BrightnessMappingStrategy brightnessMappingStrategy = mock(BrightnessMappingStrategy.class); final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class); final ScreenOffBrightnessSensorController screenOffBrightnessSensorController = mock(ScreenOffBrightnessSensorController.class); final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class); + final HdrClamper hdrClamper = mock(HdrClamper.class); + BrightnessClamperController clamperController = mock(BrightnessClamperController.class); when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX); - - DisplayPowerController.Injector injector = spy(new TestInjector(displayPowerState, animator, - automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels, - screenOffBrightnessSensorController, hbmController)); + when(clamperController.clamp(any(), anyFloat(), anyBoolean())).thenAnswer( + invocation -> DisplayBrightnessState.builder() + .setIsSlowChange(invocation.getArgument(2)) + .setBrightness(invocation.getArgument(1)) + .setMaxBrightness(PowerManager.BRIGHTNESS_MAX) + .setCustomAnimationRate(-1).build()); + + TestInjector injector = spy(new TestInjector(displayPowerState, animator, + automaticBrightnessController, wakelockController, brightnessMappingStrategy, + hysteresisLevels, screenOffBrightnessSensorController, hbmController, hdrClamper, + clamperController, mDisplayManagerFlagsMock)); final LogicalDisplay display = mock(LogicalDisplay.class); final DisplayDevice device = mock(DisplayDevice.class); @@ -1555,12 +1742,14 @@ public final class DisplayPowerControllerTest { final DisplayPowerController dpc = new DisplayPowerController( mContext, injector, mDisplayPowerCallbacksMock, mHandler, mSensorManagerMock, mDisplayBlankerMock, display, - mBrightnessTrackerMock, brightnessSetting, () -> {}, + mBrightnessTrackerMock, brightnessSetting, () -> { + }, hbmMetadata, /* bootCompleted= */ false, mDisplayManagerFlagsMock); return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting, - animator, automaticBrightnessController, screenOffBrightnessSensorController, - hbmController, hbmMetadata, brightnessMappingStrategy, injector, config); + animator, automaticBrightnessController, wakelockController, + screenOffBrightnessSensorController, hbmController, hdrClamper, clamperController, + hbmMetadata, brightnessMappingStrategy, injector, config); } /** @@ -1574,8 +1763,12 @@ public final class DisplayPowerControllerTest { public final BrightnessSetting brightnessSetting; public final DualRampAnimator<DisplayPowerState> animator; public final AutomaticBrightnessController automaticBrightnessController; + public final WakelockController wakelockController; public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController; public final HighBrightnessModeController hbmController; + + public final HdrClamper hdrClamper; + public final BrightnessClamperController clamperController; public final HighBrightnessModeMetadata hbmMetadata; public final BrightnessMappingStrategy brightnessMappingStrategy; public final DisplayPowerController.Injector injector; @@ -1585,8 +1778,11 @@ public final class DisplayPowerControllerTest { DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting, DualRampAnimator<DisplayPowerState> animator, AutomaticBrightnessController automaticBrightnessController, + WakelockController wakelockController, ScreenOffBrightnessSensorController screenOffBrightnessSensorController, HighBrightnessModeController hbmController, + HdrClamper hdrClamper, + BrightnessClamperController clamperController, HighBrightnessModeMetadata hbmMetadata, BrightnessMappingStrategy brightnessMappingStrategy, DisplayPowerController.Injector injector, @@ -1597,8 +1793,11 @@ public final class DisplayPowerControllerTest { this.brightnessSetting = brightnessSetting; this.animator = animator; this.automaticBrightnessController = automaticBrightnessController; + this.wakelockController = wakelockController; this.screenOffBrightnessSensorController = screenOffBrightnessSensorController; this.hbmController = hbmController; + this.hdrClamper = hdrClamper; + this.clamperController = clamperController; this.hbmMetadata = hbmMetadata; this.brightnessMappingStrategy = brightnessMappingStrategy; this.injector = injector; @@ -1610,24 +1809,39 @@ public final class DisplayPowerControllerTest { private final DisplayPowerState mDisplayPowerState; private final DualRampAnimator<DisplayPowerState> mAnimator; private final AutomaticBrightnessController mAutomaticBrightnessController; + private final WakelockController mWakelockController; private final BrightnessMappingStrategy mBrightnessMappingStrategy; private final HysteresisLevels mHysteresisLevels; private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; private final HighBrightnessModeController mHighBrightnessModeController; + private final HdrClamper mHdrClamper; + + private final BrightnessClamperController mClamperController; + + private final DisplayManagerFlags mFlags; + TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator, AutomaticBrightnessController automaticBrightnessController, + WakelockController wakelockController, BrightnessMappingStrategy brightnessMappingStrategy, HysteresisLevels hysteresisLevels, ScreenOffBrightnessSensorController screenOffBrightnessSensorController, - HighBrightnessModeController highBrightnessModeController) { + HighBrightnessModeController highBrightnessModeController, + HdrClamper hdrClamper, + BrightnessClamperController clamperController, + DisplayManagerFlags flags) { mDisplayPowerState = dps; mAnimator = animator; mAutomaticBrightnessController = automaticBrightnessController; + mWakelockController = wakelockController; mBrightnessMappingStrategy = brightnessMappingStrategy; mHysteresisLevels = hysteresisLevels; mScreenOffBrightnessSensorController = screenOffBrightnessSensorController; mHighBrightnessModeController = highBrightnessModeController; + mHdrClamper = hdrClamper; + mClamperController = clamperController; + mFlags = flags; } @Override @@ -1649,6 +1863,28 @@ public final class DisplayPowerControllerTest { } @Override + WakelockController getWakelockController(int displayId, + DisplayPowerCallbacks displayPowerCallbacks) { + return mWakelockController; + } + + @Override + DisplayPowerProximityStateController getDisplayPowerProximityStateController( + WakelockController wakelockController, DisplayDeviceConfig displayDeviceConfig, + Looper looper, Runnable nudgeUpdatePowerState, int displayId, + SensorManager sensorManager) { + return new DisplayPowerProximityStateController(wakelockController, + displayDeviceConfig, looper, nudgeUpdatePowerState, displayId, + sensorManager, + new DisplayPowerProximityStateController.Injector() { + @Override + DisplayPowerProximityStateController.Clock createClock() { + return mClock::now; + } + }); + } + + @Override AutomaticBrightnessController getAutomaticBrightnessController( AutomaticBrightnessController.Callbacks callbacks, Looper looper, SensorManager sensorManager, Sensor lightSensor, @@ -1710,6 +1946,23 @@ public final class DisplayPowerControllerTest { } @Override + BrightnessRangeController getBrightnessRangeController( + HighBrightnessModeController hbmController, Runnable modeChangeCallback, + DisplayDeviceConfig displayDeviceConfig, Handler handler, + DisplayManagerFlags flags, IBinder displayToken, DisplayDeviceInfo info) { + return new BrightnessRangeController(hbmController, modeChangeCallback, + displayDeviceConfig, mHdrClamper, mFlags, displayToken, info); + } + + @Override + BrightnessClamperController getBrightnessClamperController(Handler handler, + BrightnessClamperController.ClamperChangeListener clamperChangeListener, + BrightnessClamperController.DisplayDeviceData data, Context context, + DisplayManagerFlags flags) { + return mClamperController; + } + + @Override DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, SensorManager sensorManager, Resources resources) { return mDisplayWhiteBalanceControllerMock; diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java index 5c50acb13f30..a8af98f7a332 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java @@ -72,14 +72,18 @@ public class RefreshRateSettingsUtilsTest { @Test public void testFindHighestRefreshRateForDefaultDisplay() { - when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); - assertEquals(DEFAULT_REFRESH_RATE, + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + assertEquals(120, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); + } - when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); - assertEquals(120, + @Test + public void testFindHighestRefreshRate_DisplayIsNull() { + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null); + assertEquals(DEFAULT_REFRESH_RATE, RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext), /* delta= */ 0); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java index a0e5fd8e1b34..83479e28fe24 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java @@ -27,8 +27,6 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE; import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; - import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertArrayEquals; @@ -290,6 +288,7 @@ public class DisplayModeDirectorTest { }; private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY; + private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1; private static final int MODE_ID = 1; private static final float TRANSITION_POINT = 0.763f; @@ -1550,23 +1549,39 @@ public class DisplayModeDirectorTest { public void testPeakRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); - float highestRefreshRate = 130; - doReturn(highestRefreshRate).when(() -> - RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = - createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + Display.Mode[] modes1 = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 130), + }; + Display.Mode[] modes2 = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 140), + }; + SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); + supportedModesByDisplay.put(DISPLAY_ID, modes1); + supportedModesByDisplay.put(DISPLAY_ID_2, modes2); + Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); + director.injectSupportedModesByDisplay(supportedModesByDisplay); setPeakRefreshRate(Float.POSITIVE_INFINITY); - Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); - assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ - highestRefreshRate); + Vote vote2 = director.getVote(DISPLAY_ID_2, + Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); + assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test @@ -1584,32 +1599,85 @@ public class DisplayModeDirectorTest { setPeakRefreshRate(peakRefreshRate); - Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, + /* frameRateHigh= */ peakRefreshRate); + } + + @Test + public void testPeakRefreshRate_DisplayChanged() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(true); + DisplayModeDirector director = + new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 130), + }; + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setPeakRefreshRate(Float.POSITIVE_INFINITY); + + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); - assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ - peakRefreshRate); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 130); + + // The highest refresh rate of the display changes + mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 140), + }; + director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); + + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 140); } @Test public void testMinRefreshRate_FlagEnabled() { when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) .thenReturn(true); - float highestRefreshRate = 130; - doReturn(highestRefreshRate).when(() -> - RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext)); DisplayModeDirector director = - createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0); + new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + Display.Mode[] modes1 = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 130), + }; + Display.Mode[] modes2 = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 140), + }; + SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>(); + supportedModesByDisplay.put(DISPLAY_ID, modes1); + supportedModesByDisplay.put(DISPLAY_ID_2, modes2); + Sensor lightSensor = createLightSensor(); SensorManager sensorManager = createMockSensorManager(lightSensor); director.start(sensorManager); + director.injectSupportedModesByDisplay(supportedModesByDisplay); setMinRefreshRate(Float.POSITIVE_INFINITY); - Vote vote = director.getVote(Display.DEFAULT_DISPLAY, + Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + Vote vote2 = director.getVote(DISPLAY_ID_2, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); - assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate, + assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 130, + /* frameRateHigh= */ Float.POSITIVE_INFINITY); + assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 140, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @@ -1628,13 +1696,50 @@ public class DisplayModeDirectorTest { setMinRefreshRate(minRefreshRate); - Vote vote = director.getVote(Display.DEFAULT_DISPLAY, - Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate, /* frameRateHigh= */ Float.POSITIVE_INFINITY); } @Test + public void testMinRefreshRate_DisplayChanged() { + when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled()) + .thenReturn(true); + DisplayModeDirector director = + new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags); + director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON); + mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 130), + }; + + Sensor lightSensor = createLightSensor(); + SensorManager sensorManager = createMockSensorManager(lightSensor); + director.start(sensorManager); + + setMinRefreshRate(Float.POSITIVE_INFINITY); + + Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 130, + /* frameRateHigh= */ Float.POSITIVE_INFINITY); + + // The highest refresh rate of the display changes + mInjector.mDisplayInfo.supportedModes = new Display.Mode[] { + new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720, + /* refreshRate= */ 140), + }; + director.getDisplayObserver().onDisplayChanged(DISPLAY_ID); + + vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE); + assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 140, + /* frameRateHigh= */ Float.POSITIVE_INFINITY); + } + + @Test public void testSensorRegistration() { // First, configure brightness zones or DMD won't register for sensor data. final FakeDeviceConfig config = mInjector.getDeviceConfig(); @@ -3329,7 +3434,7 @@ public class DisplayModeDirectorTest { public static class FakesInjector implements DisplayModeDirector.Injector { private final FakeDeviceConfig mDeviceConfig; private final DisplayInfo mDisplayInfo; - private final Display mDisplay; + private final Map<Integer, Display> mDisplays; private boolean mDisplayInfoValid = true; private final DisplayManagerInternal mDisplayManagerInternal; private final StatusBarManagerInternal mStatusBarManagerInternal; @@ -3350,7 +3455,8 @@ public class DisplayModeDirectorTest { mDisplayInfo.defaultModeId = MODE_ID; mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID, 800, 600, /* refreshRate= */ 60)}; - mDisplay = createDisplay(DISPLAY_ID); + mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID), + DISPLAY_ID_2, createDisplay(DISPLAY_ID_2)); mDisplayManagerInternal = displayManagerInternal; mStatusBarManagerInternal = statusBarManagerInternal; mSensorManagerInternal = sensorManagerInternal; @@ -3381,12 +3487,12 @@ public class DisplayModeDirectorTest { @Override public Display getDisplay(int displayId) { - return mDisplay; + return mDisplays.get(displayId); } @Override public Display[] getDisplays() { - return new Display[] { mDisplay }; + return mDisplays.values().toArray(new Display[0]); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java index fc2e5b0981e4..0703db2ab648 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java @@ -118,7 +118,8 @@ import java.util.function.Supplier; @Presubmit public class GameManagerServiceTests { @Mock MockContext mMockContext; - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule( + SetFlagsRule.DefaultInitValueType.NULL_DEFAULT); private static final String TAG = "GameManagerServiceTests"; private static final String PACKAGE_NAME_INVALID = "com.android.app"; private static final int USER_ID_1 = 1001; diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java index c0051c6c9e17..eee37525ee37 100644 --- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java @@ -133,7 +133,8 @@ public class AnrHelperTest { verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding( eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName), eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mAuxExecutorService), - eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/, eq(mEarlyDumpFuture)); + anyBoolean() /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/, + eq(mEarlyDumpFuture)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java index feb6bd930bf3..467c15dd2a75 100644 --- a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java @@ -54,7 +54,7 @@ public final class BatteryStatsServiceTest { mBgThread.start(); File systemDir = context.getCacheDir(); Handler handler = new Handler(mBgThread.getLooper()); - mBatteryStatsService = new BatteryStatsService(context, systemDir, handler); + mBatteryStatsService = new BatteryStatsService(context, systemDir); } @After diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index 276c8321fb65..e1f490ae3e2f 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -341,7 +341,8 @@ public class VirtualDeviceManagerServiceTest { mSetFlagsRule.initAllFlagsToReleaseConfigDefault(); doReturn(true).when(mInputManagerInternalMock).setVirtualMousePointerDisplayId(anyInt()); - doNothing().when(mInputManagerInternalMock).setPointerAcceleration(anyFloat(), anyInt()); + doNothing().when(mInputManagerInternalMock) + .setMousePointerAccelerationEnabled(anyBoolean(), anyInt()); doNothing().when(mInputManagerInternalMock).setPointerIconVisible(anyBoolean(), anyInt()); LocalServices.removeServiceForTest(InputManagerInternal.class); LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock); 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 6b85a327e61b..95a9610b15d7 100644 --- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java @@ -25,25 +25,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import android.content.ContentResolver; import android.content.Context; -import android.content.ContextWrapper; -import android.content.IContentProvider; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.os.Build; import android.os.LocaleList; import android.os.Parcel; -import android.os.UserHandle; -import android.provider.Settings; -import android.test.mock.MockContentResolver; import android.text.TextUtils; import android.util.ArrayMap; import android.util.IntArray; @@ -1243,63 +1233,6 @@ public class InputMethodUtilsTest { imeId, createSubtypeHashCodeArrayFromStr(enabledSubtypeHashCodesStr))); } - private static TestContext createMockContext(int userId) { - return new TestContext(InstrumentationRegistry.getInstrumentation() - .getTargetContext(), userId); - } - - private static class TestContext extends ContextWrapper { - private int mUserId; - private ContentResolver mResolver; - private Resources mResources; - - private static TestContext sSecondaryUserContext; - - TestContext(@NonNull Context context, int userId) { - super(context); - mUserId = userId; - mResolver = mock(MockContentResolver.class); - when(mResolver.acquireProvider(Settings.Secure.CONTENT_URI)).thenReturn( - mock(IContentProvider.class)); - mResources = mock(Resources.class); - - final Configuration configuration = new Configuration(); - if (userId == 0) { - configuration.setLocale(LOCALE_EN_US); - } else { - configuration.setLocale(LOCALE_FR_CA); - } - doReturn(configuration).when(mResources).getConfiguration(); - } - - @Override - public Context createContextAsUser(UserHandle user, int flags) { - if (user.getIdentifier() != UserHandle.USER_SYSTEM) { - return sSecondaryUserContext = new TestContext(this, user.getIdentifier()); - } - return this; - } - - @Override - public int getUserId() { - return mUserId; - } - - @Override - public ContentResolver getContentResolver() { - return mResolver; - } - - @Override - public Resources getResources() { - return mResources; - } - - static Context getSecondaryUserContext() { - return sSecondaryUserContext; - } - } - private static void verifySplitEnabledImeStr(@NonNull String enabledImeStr, @NonNull String... expected) { final ArrayList<String> actual = new ArrayList<>(); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java index c10c3c28e9dd..9b25f58acc96 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java @@ -183,7 +183,6 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase { assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isFalse(); verify(mDb, times(2)).disableHistory(); } - @Test public void testAddProfile_historyEnabledInPrimary() { // create a history @@ -610,4 +609,14 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase { assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse(); } + @Test + public void testDelayedPackageRemoval_userLocked() { + String pkg = "pkg"; + mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg); + mHistoryManager.onUserUnlocked(USER_SYSTEM); + mHistoryManager.onUserStopped(USER_SYSTEM); + mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg); + + // no exception, yay + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index 53ca704b6d86..bf850cfe04db 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -44,8 +44,10 @@ import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.drawable.Icon; +import android.os.BadParcelableException; import android.os.Binder; import android.os.Build; +import android.os.DeadObjectException; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; @@ -99,6 +101,20 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { } @Test + public void testGetActiveNotifications_handlesBinderErrors() throws RemoteException { + TestListenerService service = new TestListenerService(); + INotificationManager noMan = service.getNoMan(); + when(noMan.getActiveNotificationsFromListener(any(), any(), anyInt())) + .thenThrow(new BadParcelableException("oops", new DeadObjectException(""))); + + assertNotNull(service.getActiveNotifications()); + assertNotNull(service.getActiveNotifications(NotificationListenerService.TRIM_FULL)); + assertNotNull(service.getActiveNotifications(new String[0])); + assertNull(service.getActiveNotifications( + new String[0], NotificationListenerService.TRIM_LIGHT)); + } + + @Test public void testGetActiveNotifications_preP_mapsExtraPeople() throws RemoteException { TestListenerService service = new TestListenerService(); service.attachBaseContext(mContext); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index 177d64555899..dd252f3ffd20 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -60,6 +60,7 @@ import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.time.Instant; @SmallTest @RunWith(AndroidJUnit4.class) @@ -407,6 +408,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.userModifiedFields = 16; rule.iconResName = ICON_RES_NAME; rule.triggerDescription = TRIGGER_DESC; + rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); Parcel parcel = Parcel.obtain(); rule.writeToParcel(parcel, 0); @@ -432,9 +434,10 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.userModifiedFields, parceled.userModifiedFields); assertEquals(rule.triggerDescription, parceled.triggerDescription); assertEquals(rule.zenPolicy, parceled.zenPolicy); + assertEquals(rule.deletionInstant, parceled.deletionInstant); + assertEquals(rule, parceled); assertEquals(rule.hashCode(), parceled.hashCode()); - } @Test @@ -510,6 +513,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.userModifiedFields = 4; rule.iconResName = ICON_RES_NAME; rule.triggerDescription = TRIGGER_DESC; + rule.deletionInstant = Instant.ofEpochMilli(1701790147000L); ByteArrayOutputStream baos = new ByteArrayOutputStream(); writeRuleXml(rule, baos); @@ -539,6 +543,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.userModifiedFields, fromXml.userModifiedFields); assertEquals(rule.triggerDescription, fromXml.triggerDescription); assertEquals(rule.iconResName, fromXml.iconResName); + assertEquals(rule.deletionInstant, fromXml.deletionInstant); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java index 7e92e427b9a4..9d7cf53e62db 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java @@ -65,18 +65,22 @@ import java.util.Set; @TestableLooper.RunWithLooper public class ZenModeDiffTest extends UiServiceTestCase { // Base set of exempt fields independent of fields that are enabled/disabled via flags. - // version is not included in the diff; manual & automatic rules have special handling + // version is not included in the diff; manual & automatic rules have special handling; + // deleted rules are not included in the diff. public static final Set<String> ZEN_MODE_CONFIG_EXEMPT_FIELDS = - Set.of("version", "manualRule", "automaticRules"); + android.app.Flags.modesApi() + ? Set.of("version", "manualRule", "automaticRules", "deletedRules") + : Set.of("version", "manualRule", "automaticRules"); // Differences for flagged fields are only generated if the flag is enabled. - // TODO: b/310620812 - Remove this exempt list when flag is inlined. + // "Metadata" fields (userModifiedFields, deletionInstant) are not compared. private static final Set<String> ZEN_RULE_EXEMPT_FIELDS = android.app.Flags.modesApi() - ? Set.of() + ? Set.of("userModifiedFields", "deletionInstant") : Set.of(RuleDiff.FIELD_TYPE, RuleDiff.FIELD_TRIGGER_DESCRIPTION, RuleDiff.FIELD_ICON_RES, RuleDiff.FIELD_ALLOW_MANUAL, - RuleDiff.FIELD_ZEN_DEVICE_EFFECTS, RuleDiff.FIELD_USER_MODIFIED_FIELDS); + RuleDiff.FIELD_ZEN_DEVICE_EFFECTS, "userModifiedFields", + "deletionInstant"); // allowPriorityChannels is flagged by android.app.modes_api public static final Set<String> ZEN_MODE_CONFIG_FLAGGED_FIELDS = diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 0224ff35219b..9e3e336fa12f 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -43,6 +43,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; import static android.provider.Settings.Global.ZEN_MODE_OFF; @@ -92,6 +93,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; +import android.Manifest; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.AppGlobals; @@ -104,6 +106,7 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; @@ -116,6 +119,7 @@ import android.media.VolumePolicy; import android.net.Uri; import android.os.Parcel; import android.os.Process; +import android.os.SimpleClock; import android.os.UserHandle; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; @@ -172,12 +176,16 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; @SmallTest @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. @@ -232,6 +240,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Mock PackageManager mPackageManager; private Resources mResources; private TestableLooper mTestableLooper; + private final TestClock mTestClock = new TestClock(); private ZenModeHelper mZenModeHelper; private ContentResolver mContentResolver; @Mock DeviceEffectsApplier mDeviceEffectsApplier; @@ -269,7 +278,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mConditionProviders.addSystemProvider(new CountdownConditionProvider()); mConditionProviders.addSystemProvider(new ScheduleConditionProvider()); mZenModeEventLogger = new ZenModeEventLoggerFake(mPackageManager); - mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(), + mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(), mTestClock, mConditionProviders, mTestFlagResolver, mZenModeEventLogger); ResolveInfo ri = new ResolveInfo(); @@ -1198,7 +1207,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void ruleUidAutomaticZenRuleRemovedUpdatesCache() throws Exception { when(mContext.checkCallingPermission(anyString())) - .thenReturn(PackageManager.PERMISSION_GRANTED); + .thenReturn(PERMISSION_GRANTED); setupZenConfig(); // one enabled automatic rule @@ -1780,7 +1789,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testDoNotUpdateModifiedDefaultAutoRule() { // mDefaultConfig is set to default config in setup by getDefaultConfigParser when(mContext.checkCallingPermission(anyString())) - .thenReturn(PackageManager.PERMISSION_GRANTED); + .thenReturn(PERMISSION_GRANTED); // shouldn't update rule that's been modified ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule(); @@ -1806,7 +1815,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testDoNotUpdateEnabledDefaultAutoRule() { // mDefaultConfig is set to default config in setup by getDefaultConfigParser when(mContext.checkCallingPermission(anyString())) - .thenReturn(PackageManager.PERMISSION_GRANTED); + .thenReturn(PERMISSION_GRANTED); // shouldn't update the rule that's enabled ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule(); @@ -1833,7 +1842,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // mDefaultConfig is set to default config in setup by getDefaultConfigParser final String defaultRuleName = "rule name test"; when(mContext.checkCallingPermission(anyString())) - .thenReturn(PackageManager.PERMISSION_GRANTED); + .thenReturn(PERMISSION_GRANTED); // will update rule that is not enabled and modified ZenModeConfig.ZenRule customDefaultRule = new ZenModeConfig.ZenRule(); @@ -4318,6 +4327,324 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void removeAndAddAutomaticZenRule_wasCustomized_isRestored() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + + // Start with a rule. + mZenModeHelper.mConfig.automaticRules.clear(); + mTestClock.setNowMillis(1000); + AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build()) + .build(); + String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID); + assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000); + assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).canUpdate()).isTrue(); + + // User customizes it. + AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule) + .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build()) + .build(); + mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate", + Process.SYSTEM_UID); + + // App deletes it. + mTestClock.advanceByMillis(1000); + mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it", + CUSTOM_PKG_UID); + assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0); + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1); + + // App adds it again. + mTestClock.advanceByMillis(1000); + String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID); + + // Verify that the rule was restored: + // - id and creation time is the same as the original one. + // - ZenPolicy is the one that the user had set. + // - rule still has the user-modified fields. + AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId); + assertThat(finalRule.getCreationTime()).isEqualTo(1000); // And not 3000. + assertThat(newRuleId).isEqualTo(ruleId); + assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS); + assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo( + ZenPolicy.STATE_ALLOW); + assertThat(finalRule.getUserModifiedFields()).isEqualTo( + AutomaticZenRule.FIELD_INTERRUPTION_FILTER); + assertThat(finalRule.getZenPolicy().getUserModifiedFields()).isEqualTo( + ZenPolicy.FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS); + + // Also, we discarded the "deleted rule" since we already used it for restoration. + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0); + } + + @Test + public void removeAndAddAutomaticZenRule_wasNotCustomized_isNotRestored() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + + // Start with a single rule. + mZenModeHelper.mConfig.automaticRules.clear(); + mTestClock.setNowMillis(1000); + AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build()) + .build(); + String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID); + assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000); + + // App deletes it. + mTestClock.advanceByMillis(1000); + mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it", + CUSTOM_PKG_UID); + assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0); + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0); + + // App adds it again. + mTestClock.advanceByMillis(1000); + String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID); + + // Verify that the rule was recreated. This means id and creation time are new. + AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId); + assertThat(finalRule.getCreationTime()).isEqualTo(3000); + assertThat(newRuleId).isNotEqualTo(ruleId); + } + + @Test + public void removeAndAddAutomaticZenRule_recreatedButNotByApp_isNotRestored() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + + // Start with a single rule. + mZenModeHelper.mConfig.automaticRules.clear(); + mTestClock.setNowMillis(1000); + AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build()) + .build(); + String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID); + assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000); + + // User customizes it. + mTestClock.advanceByMillis(1000); + AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule) + .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build()) + .build(); + mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate", + Process.SYSTEM_UID); + + // App deletes it. + mTestClock.advanceByMillis(1000); + mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it", + CUSTOM_PKG_UID); + assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0); + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1); + + // User creates it again (unusual case, but ok). + mTestClock.advanceByMillis(1000); + String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_USER, "add it anew", CUSTOM_PKG_UID); + + // Verify that the rule was recreated. This means id and creation time are new, and the rule + // matches the latest data supplied to addAZR. + AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId); + assertThat(finalRule.getCreationTime()).isEqualTo(4000); + assertThat(newRuleId).isNotEqualTo(ruleId); + assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY); + assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo( + ZenPolicy.STATE_DISALLOW); + + // Also, we discarded the "deleted rule" since we're not interested in recreating it. + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0); + } + + @Test + public void removeAndAddAutomaticZenRule_removedByUser_isNotRestored() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + + // Start with a single rule. + mZenModeHelper.mConfig.automaticRules.clear(); + mTestClock.setNowMillis(1000); + AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID) + .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build()) + .build(); + String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID); + assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000); + + // User customizes it. + mTestClock.advanceByMillis(1000); + AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule) + .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS) + .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build()) + .build(); + mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate", + Process.SYSTEM_UID); + + // User deletes it. + mTestClock.advanceByMillis(1000); + mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_USER, "delete it", + CUSTOM_PKG_UID); + assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0); + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0); + + // App creates it again. + mTestClock.advanceByMillis(1000); + String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule, + UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID); + + // Verify that the rule was recreated. This means id and creation time are new. + AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId); + assertThat(finalRule.getCreationTime()).isEqualTo(4000); + assertThat(newRuleId).isNotEqualTo(ruleId); + } + + @Test + public void removeAutomaticZenRule_preservedForRestoringByPackageAndConditionId() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS, + PERMISSION_GRANTED); // So that canManageAZR passes although packages don't match. + mZenModeHelper.mConfig.automaticRules.clear(); + + // Start with a bunch of customized rules where conditionUris are not unique. + String id1 = mZenModeHelper.addAutomaticZenRule("pkg1", + new AutomaticZenRule.Builder("Test1", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + String id2 = mZenModeHelper.addAutomaticZenRule("pkg1", + new AutomaticZenRule.Builder("Test2", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + String id3 = mZenModeHelper.addAutomaticZenRule("pkg1", + new AutomaticZenRule.Builder("Test3", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + String id4 = mZenModeHelper.addAutomaticZenRule("pkg2", + new AutomaticZenRule.Builder("Test4", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + String id5 = mZenModeHelper.addAutomaticZenRule("pkg2", + new AutomaticZenRule.Builder("Test5", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + for (ZenRule zenRule : mZenModeHelper.mConfig.automaticRules.values()) { + zenRule.userModifiedFields = AutomaticZenRule.FIELD_INTERRUPTION_FILTER; + } + + mZenModeHelper.removeAutomaticZenRule(id1, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID); + mZenModeHelper.removeAutomaticZenRule(id2, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID); + mZenModeHelper.removeAutomaticZenRule(id3, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID); + mZenModeHelper.removeAutomaticZenRule(id4, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID); + mZenModeHelper.removeAutomaticZenRule(id5, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID); + + assertThat(mZenModeHelper.mConfig.deletedRules.keySet()) + .containsExactly("pkg1|uri1", "pkg1|uri2", "pkg2|uri1"); + assertThat(mZenModeHelper.mConfig.deletedRules.values().stream().map(zr -> zr.name) + .collect(Collectors.toList())) + .containsExactly("Test1", "Test3", "Test5"); + } + + @Test + public void removeAllZenRules_preservedForRestoring() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + mZenModeHelper.mConfig.automaticRules.clear(); + + mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + new AutomaticZenRule.Builder("Test1", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), + new AutomaticZenRule.Builder("Test2", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP, + "add it", CUSTOM_PKG_UID); + + for (ZenRule zenRule : mZenModeHelper.mConfig.automaticRules.values()) { + zenRule.userModifiedFields = AutomaticZenRule.FIELD_INTERRUPTION_FILTER; + } + + mZenModeHelper.removeAutomaticZenRules(mContext.getPackageName(), UPDATE_ORIGIN_APP, + "begone", CUSTOM_PKG_UID); + + assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(2); + } + + @Test + public void removeAllZenRules_fromSystem_deletesPreservedRulesToo() { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + mZenModeHelper.mConfig.automaticRules.clear(); + + // Start with deleted rules from 2 different packages. + Instant now = Instant.ofEpochMilli(1701796461000L); + ZenRule pkg1Rule = newZenRule("pkg1", now.minus(1, ChronoUnit.DAYS), now); + ZenRule pkg2Rule = newZenRule("pkg2", now.minus(2, ChronoUnit.DAYS), now); + mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg1Rule), pkg1Rule); + mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg2Rule), pkg2Rule); + + mZenModeHelper.removeAutomaticZenRules("pkg1", + UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "goodbye pkg1", Process.SYSTEM_UID); + + // Preserved rules from pkg1 are gone; those from pkg2 are still there. + assertThat(mZenModeHelper.mConfig.deletedRules.values().stream().map(r -> r.pkg) + .collect(Collectors.toSet())).containsExactly("pkg2"); + } + + @Test + public void testRuleCleanup() throws Exception { + mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); + Instant now = Instant.ofEpochMilli(1701796461000L); + Instant yesterday = now.minus(1, ChronoUnit.DAYS); + Instant aWeekAgo = now.minus(7, ChronoUnit.DAYS); + Instant twoMonthsAgo = now.minus(60, ChronoUnit.DAYS); + mTestClock.setNowMillis(now.toEpochMilli()); + + when(mPackageManager.getPackageInfo(eq("good_pkg"), anyInt())) + .thenReturn(new PackageInfo()); + when(mPackageManager.getPackageInfo(eq("bad_pkg"), anyInt())) + .thenThrow(new PackageManager.NameNotFoundException("bad_pkg is not here")); + + // Set up a config for another user containing: + ZenModeConfig config = new ZenModeConfig(); + config.user = 42; + mZenModeHelper.mConfigs.put(42, config); + // okay rules (not deleted, package exists, with a range of creation dates). + config.automaticRules.put("ar1", newZenRule("good_pkg", now, null)); + config.automaticRules.put("ar2", newZenRule("good_pkg", yesterday, null)); + config.automaticRules.put("ar3", newZenRule("good_pkg", twoMonthsAgo, null)); + // newish rules for a missing package + config.automaticRules.put("ar4", newZenRule("bad_pkg", yesterday, null)); + // oldish rules belonging to a missing package + config.automaticRules.put("ar5", newZenRule("bad_pkg", aWeekAgo, null)); + // rules deleted recently + config.deletedRules.put("del1", newZenRule("good_pkg", twoMonthsAgo, yesterday)); + config.deletedRules.put("del2", newZenRule("good_pkg", twoMonthsAgo, aWeekAgo)); + // rules deleted a long time ago + config.deletedRules.put("del3", newZenRule("good_pkg", twoMonthsAgo, twoMonthsAgo)); + // rules for a missing package, created recently and deleted recently + config.deletedRules.put("del4", newZenRule("bad_pkg", yesterday, now)); + // rules for a missing package, created a long time ago and deleted recently + config.deletedRules.put("del5", newZenRule("bad_pkg", twoMonthsAgo, now)); + // rules for a missing package, created a long time ago and deleted a long time ago + config.deletedRules.put("del6", newZenRule("bad_pkg", twoMonthsAgo, twoMonthsAgo)); + + mZenModeHelper.onUserUnlocked(42); // copies config and cleans it up. + + assertThat(mZenModeHelper.mConfig.automaticRules.keySet()) + .containsExactly("ar1", "ar2", "ar3", "ar4"); + assertThat(mZenModeHelper.mConfig.deletedRules.keySet()) + .containsExactly("del1", "del2", "del4"); + } + + private static ZenRule newZenRule(String pkg, Instant createdAt, @Nullable Instant deletedAt) { + ZenRule rule = new ZenRule(); + rule.pkg = pkg; + rule.creationTime = createdAt.toEpochMilli(); + rule.deletionInstant = deletedAt; + // Plus stuff so that isValidAutomaticRule() passes + rule.name = "A rule from " + pkg + " created on " + createdAt; + rule.conditionId = Uri.parse(rule.name); + return rule; + } + + @Test public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() { mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); mZenModeHelper.mConfig.automaticRules.clear(); @@ -4919,4 +5246,25 @@ public class ZenModeHelperTest extends UiServiceTestCase { return parser.nextTag(); } } + + private static class TestClock extends SimpleClock { + private long mNowMillis = 441644400000L; + + private TestClock() { + super(ZoneOffset.UTC); + } + + @Override + public long millis() { + return mNowMillis; + } + + private void setNowMillis(long millis) { + mNowMillis = millis; + } + + private void advanceByMillis(long millis) { + mNowMillis += millis; + } + } } 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 f5282cb492f0..9bb2da0ff70c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -3309,7 +3309,7 @@ public class ActivityRecordTests extends WindowTestsBase { // keyguard to back to the app, expect IME insets is not frozen app.mActivityRecord.commitVisibility(true, false); mDisplayContent.updateImeInputAndControlTarget(app); - mDisplayContent.mWmService.mRoot.performSurfacePlacement(); + performSurfacePlacementAndWaitForWindowAnimator(); assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); @@ -3358,7 +3358,7 @@ public class ActivityRecordTests extends WindowTestsBase { mDisplayContent.setImeLayeringTarget(app2); app2.mActivityRecord.commitVisibility(true, false); mDisplayContent.updateImeInputAndControlTarget(app2); - mDisplayContent.mWmService.mRoot.performSurfacePlacement(); + performSurfacePlacementAndWaitForWindowAnimator(); // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets // to client if the app didn't request IME visible. @@ -3412,7 +3412,7 @@ public class ActivityRecordTests extends WindowTestsBase { // frozen until the input started. mDisplayContent.setImeLayeringTarget(app1); mDisplayContent.updateImeInputAndControlTarget(app1); - mDisplayContent.mWmService.mRoot.performSurfacePlacement(); + performSurfacePlacementAndWaitForWindowAnimator(); assertEquals(app1, mDisplayContent.getImeInputTarget()); assertFalse(activity1.mImeInsetsFrozenUntilStartInput); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java index 98f18433e53d..03d30294e1d8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivitySnapshotControllerTests.java @@ -17,13 +17,31 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import android.content.ComponentName; +import android.graphics.ColorSpace; +import android.graphics.Point; +import android.graphics.Rect; +import android.hardware.HardwareBuffer; import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; +import android.view.Surface; +import android.window.TaskSnapshot; import androidx.test.filters.SmallTest; @@ -32,6 +50,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.ArrayList; +import java.util.Arrays; /** * Test class for {@link ActivitySnapshotController}. @@ -45,6 +64,7 @@ import java.util.ArrayList; public class ActivitySnapshotControllerTests extends WindowTestsBase { private ActivitySnapshotController mActivitySnapshotController; + @Before public void setUp() throws Exception { spyOn(mWm.mSnapshotController.mActivitySnapshotController); @@ -154,4 +174,90 @@ public class ActivitySnapshotControllerTests extends WindowTestsBase { assertEquals(openingWindowBelow.mActivityRecord, mActivitySnapshotController.mPendingLoadActivity.valueAt(0)); } + + /** + * Simulate multiple TaskFragments inside a task. + */ + @Test + public void testMultipleActivitiesLoadSnapshot() { + final Task testTask = createTask(mDisplayContent); + final ActivityRecord activityA = createActivityRecord(testTask); + final ActivityRecord activityB = createActivityRecord(testTask); + final ActivityRecord activityC = createActivityRecord(testTask); + final TaskSnapshot taskSnapshot = createSnapshot(); + + final int[] mixedCode = new int[3]; + mixedCode[0] = ActivitySnapshotController.getSystemHashCode(activityA); + mixedCode[1] = ActivitySnapshotController.getSystemHashCode(activityB); + mixedCode[2] = ActivitySnapshotController.getSystemHashCode(activityC); + + mActivitySnapshotController.addUserSavedFile(testTask.mUserId, taskSnapshot, mixedCode); + mActivitySnapshotController.mCache.putSnapshot(activityA, taskSnapshot); + mActivitySnapshotController.mCache.putSnapshot(activityB, taskSnapshot); + mActivitySnapshotController.mCache.putSnapshot(activityC, taskSnapshot); + + assertTrue(mActivitySnapshotController.hasRecord(activityA)); + assertTrue(mActivitySnapshotController.hasRecord(activityB)); + + // If A is removed, B and C should also be removed because they share the same snapshot. + mActivitySnapshotController.onAppRemoved(activityA); + assertFalse(mActivitySnapshotController.hasRecord(activityA)); + assertFalse(mActivitySnapshotController.hasRecord(activityB)); + final ActivityRecord[] singleActivityList = new ActivityRecord[1]; + singleActivityList[0] = activityA; + assertNull(mActivitySnapshotController.getSnapshot(singleActivityList)); + singleActivityList[0] = activityB; + assertNull(mActivitySnapshotController.getSnapshot(singleActivityList)); + final ActivityRecord[] activities = new ActivityRecord[3]; + activities[0] = activityA; + activities[1] = activityB; + activities[2] = activityC; + assertNull(mActivitySnapshotController.getSnapshot(activities)); + + // Reset and test load snapshot + mActivitySnapshotController.addUserSavedFile(testTask.mUserId, taskSnapshot, mixedCode); + // Request to load by B, nothing will be loaded because the snapshot was [A,B,C]. + mActivitySnapshotController.mPendingLoadActivity.add(activityB); + mActivitySnapshotController.loadActivitySnapshot(); + verify(mActivitySnapshotController, never()).loadSnapshotInner(any(), any()); + + // Able to load snapshot when requesting for all A, B, C + mActivitySnapshotController.mPendingLoadActivity.clear(); + mActivitySnapshotController.mPendingLoadActivity.add(activityA); + mActivitySnapshotController.mPendingLoadActivity.add(activityB); + mActivitySnapshotController.mPendingLoadActivity.add(activityC); + final ArraySet<ActivityRecord> verifyList = new ArraySet<>(); + verifyList.add(activityA); + verifyList.add(activityB); + verifyList.add(activityC); + mActivitySnapshotController.loadActivitySnapshot(); + verify(mActivitySnapshotController).loadSnapshotInner(argThat( + argument -> { + final ArrayList<ActivityRecord> argumentList = new ArrayList<>( + Arrays.asList(argument)); + return verifyList.containsAll(argumentList) + && argumentList.containsAll(verifyList); + }), + any()); + + for (int i = activities.length - 1; i >= 0; --i) { + mActivitySnapshotController.mCache.putSnapshot(activities[i], taskSnapshot); + } + // The loaded snapshot can be retrieved only if the activities match exactly. + singleActivityList[0] = activityB; + assertNull(mActivitySnapshotController.getSnapshot(singleActivityList)); + assertEquals(taskSnapshot, mActivitySnapshotController.getSnapshot(activities)); + } + + private TaskSnapshot createSnapshot() { + HardwareBuffer buffer = mock(HardwareBuffer.class); + doReturn(100).when(buffer).getWidth(); + doReturn(100).when(buffer).getHeight(); + return new TaskSnapshot(1, 0 /* captureTime */, new ComponentName("", ""), buffer, + ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT, + Surface.ROTATION_0, new Point(100, 100), new Rect() /* contentInsets */, + new Rect() /* letterboxInsets*/, false /* isLowResolution */, + true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN, 0 /* mSystemUiVisibility */, + false /* isTranslucent */, false /* hasImeSurface */); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index d83824a39730..402cbccbca01 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -742,7 +742,7 @@ public class BackNavigationControllerTests extends WindowTestsBase { MockitoSession mockitoSession = mockitoSession().mockStatic(BackNavigationController.class) .strictness(Strictness.LENIENT).startMocking(); - doReturn(taskSnapshot).when(() -> BackNavigationController.getSnapshot(any())); + doReturn(taskSnapshot).when(() -> BackNavigationController.getSnapshot(any(), any())); when(resourcesSpy.getBoolean( com.android.internal.R.bool.config_predictShowStartingSurface)) .thenReturn(preferWindowlessSurface); diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java index 8bd54731c7c2..2d3c4bbe8bdc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java @@ -28,6 +28,7 @@ import android.os.HandlerExecutor; import android.os.Looper; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; +import android.util.Log; import androidx.test.filters.MediumTest; @@ -147,6 +148,8 @@ public class SplashScreenExceptionListTest { private void setExceptionListAndWaitForCallback(String commaSeparatedList) { CountDownLatch latch = new CountDownLatch(1); mOnUpdateDeviceConfig = rawList -> { + Log.i(getClass().getSimpleName(), "updateDeviceConfig expected=" + + commaSeparatedList + " actual=" + rawList); if (commaSeparatedList.equals(rawList)) { latch.countDown(); } @@ -155,7 +158,7 @@ public class SplashScreenExceptionListTest { KEY_SPLASH_SCREEN_EXCEPTION_LIST, commaSeparatedList, false); try { assertTrue("Timed out waiting for DeviceConfig to be updated.", - latch.await(1, TimeUnit.SECONDS)); + latch.await(5, TimeUnit.SECONDS)); } catch (InterruptedException e) { Assert.fail(e.getMessage()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index e9fe4bb91329..22ddf8420121 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -53,6 +53,7 @@ import android.graphics.Rect; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; +import android.view.View; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentInfo; @@ -695,4 +696,75 @@ public class TaskFragmentTest extends WindowTestsBase { mTaskFragment.getDimBounds(dimBounds); assertEquals(taskFragmentBounds, dimBounds); } + + @Test + public void testMoveFocusToAdjacentWindow() { + // Setup two activities in ActivityEmbedding split. + final Task task = createTask(mDisplayContent); + final TaskFragment taskFragmentLeft = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .createActivityCount(2) + .setOrganizer(mOrganizer) + .setFragmentToken(new Binder()) + .build(); + final TaskFragment taskFragmentRight = new TaskFragmentBuilder(mAtm) + .setParentTask(task) + .createActivityCount(1) + .setOrganizer(mOrganizer) + .setFragmentToken(new Binder()) + .build(); + taskFragmentLeft.setAdjacentTaskFragment(taskFragmentRight); + taskFragmentLeft.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + taskFragmentRight.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + task.setBounds(0, 0, 1200, 1000); + taskFragmentLeft.setBounds(0, 0, 600, 1000); + taskFragmentRight.setBounds(600, 0, 1200, 1000); + final ActivityRecord appLeftTop = taskFragmentLeft.getTopMostActivity(); + final ActivityRecord appLeftBottom = taskFragmentLeft.getBottomMostActivity(); + final ActivityRecord appRightTop = taskFragmentRight.getTopMostActivity(); + appLeftTop.setVisibleRequested(true); + appRightTop.setVisibleRequested(true); + final WindowState winLeftTop = createAppWindow(appLeftTop, "winLeftTop"); + final WindowState winLeftBottom = createAppWindow(appLeftBottom, "winLeftBottom"); + final WindowState winRightTop = createAppWindow(appRightTop, "winRightTop"); + winLeftTop.setHasSurface(true); + winRightTop.setHasSurface(true); + + taskFragmentLeft.setResumedActivity(appLeftTop, "test"); + taskFragmentRight.setResumedActivity(appRightTop, "test"); + appLeftTop.setState(RESUMED, "test"); + appRightTop.setState(RESUMED, "test"); + mDisplayContent.mFocusedApp = appRightTop; + + // Make the appLeftTop be the focused activity and ensure the focused app is updated. + appLeftTop.moveFocusableActivityToTop("test"); + assertEquals(winLeftTop, mDisplayContent.mCurrentFocus); + + // Send request from a non-focused window with valid direction. + assertFalse(mWm.moveFocusToAdjacentWindow(null, winLeftBottom.mClient, View.FOCUS_RIGHT)); + // The focus should remain the same. + assertEquals(winLeftTop, mDisplayContent.mCurrentFocus); + + // Send request from the focused window with valid direction. + assertTrue(mWm.moveFocusToAdjacentWindow(null, winLeftTop.mClient, View.FOCUS_RIGHT)); + // The focus should change. + assertEquals(winRightTop, mDisplayContent.mCurrentFocus); + + // Send request from the focused window with invalid direction. + assertFalse(mWm.moveFocusToAdjacentWindow(null, winRightTop.mClient, View.FOCUS_UP)); + // The focus should remain the same. + assertEquals(winRightTop, mDisplayContent.mCurrentFocus); + + // Send request from the focused window with valid direction. + assertTrue(mWm.moveFocusToAdjacentWindow(null, winRightTop.mClient, View.FOCUS_BACKWARD)); + // The focus should change. + assertEquals(winLeftTop, mDisplayContent.mCurrentFocus); + } + + private WindowState createAppWindow(ActivityRecord app, String name) { + final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, app, name, + 0 /* ownerId */, false /* ownerCanAddInternalSystemWindow */, new TestIWindow()); + mWm.mWindowMap.put(win.mClient.asBinder(), win); + return win; + } } 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 60e84b03ec89..9c421ba29796 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -1054,6 +1054,19 @@ class WindowTestsBase extends SystemServiceTestsBase { } /** + * Performs surface placement and waits for WindowAnimator to complete the frame. It is used + * to execute the callbacks if the surface placement is expected to add some callbacks via + * {@link WindowAnimator#addAfterPrepareSurfacesRunnable}. + */ + void performSurfacePlacementAndWaitForWindowAnimator() { + mWm.mAnimator.ready(); + if (!mWm.mWindowPlacerLocked.isTraversalScheduled()) { + mRootWindowContainer.performSurfacePlacement(); + } + waitUntilWindowAnimatorIdle(); + } + + /** * Avoids rotating screen disturbed by some conditions. It is usually used for the default * display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions). * diff --git a/services/usb/lint-baseline.xml b/services/usb/lint-baseline.xml index c2c0a350d5ad..62a2ee56a0cf 100644 --- a/services/usb/lint-baseline.xml +++ b/services/usb/lint-baseline.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev"> +<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01"> <issue id="NonUserGetterCalled" @@ -12,4 +12,4 @@ column="42"/> </issue> -</issues> +</issues>
\ No newline at end of file diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java index 8773cabeeb92..1df7012c44f8 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/PhoneCallStateHandler.java @@ -24,6 +24,7 @@ import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.telephony.flags.Flags; import java.util.ArrayList; import java.util.List; @@ -117,12 +118,28 @@ public class PhoneCallStateHandler { private boolean checkCallStatus() { List<SubscriptionInfo> infoList = mSubscriptionManager.getActiveSubscriptionInfoList(); if (infoList == null) return false; - return infoList.stream() - .filter(s -> (s.getSubscriptionId() != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) - .anyMatch(s -> isCallOngoingFromState( - mTelephonyManager - .createForSubscriptionId(s.getSubscriptionId()) - .getCallStateForSubscription())); + if (!Flags.enforceTelephonyFeatureMapping()) { + return infoList.stream() + .filter(s -> (s.getSubscriptionId() + != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) + .anyMatch(s -> isCallOngoingFromState( + mTelephonyManager + .createForSubscriptionId(s.getSubscriptionId()) + .getCallStateForSubscription())); + } else { + return infoList.stream() + .filter(s -> (s.getSubscriptionId() + != SubscriptionManager.INVALID_SUBSCRIPTION_ID)) + .anyMatch(s -> { + try { + return isCallOngoingFromState(mTelephonyManager + .createForSubscriptionId(s.getSubscriptionId()) + .getCallStateForSubscription()); + } catch (UnsupportedOperationException e) { + return false; + } + }); + } } private void updateTelephonyListeners() { diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 250c3a54c928..2a6ac98b4d98 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -196,7 +196,7 @@ public final class TelephonyPermissions { // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage, + return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED; } @@ -249,7 +249,7 @@ public final class TelephonyPermissions { // We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage, + return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED; } @@ -521,7 +521,7 @@ public final class TelephonyPermissions { // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been // revoked. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); - return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage, + return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage, callingPackageName, null) == AppOpsManager.MODE_ALLOWED; } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index c7b84a3b9530..73c26a3e5fc9 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -9683,6 +9683,17 @@ public class CarrierConfigManager { "parameters_used_for_ntn_lte_signal_bar_int"; /** + * Indicating whether plmns associated with carrier satellite can be exposed to user when + * manually scanning available cellular network. + * If key is {@code true}, satellite plmn should not be exposed to user and should be + * automatically set, {@code false} otherwise. Default value is {@code true}. + * + * @hide + */ + public static final String KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL = + "remove_satellite_plmn_in_manual_network_scan_bool"; + + /** * Indicating whether DUN APN should be disabled when the device is roaming. In that case, * the default APN (i.e. internet) will be used for tethering. * @@ -10787,6 +10798,7 @@ public class CarrierConfigManager { }); sDefaults.putInt(KEY_PARAMETERS_USED_FOR_NTN_LTE_SIGNAL_BAR_INT, CellSignalStrengthLte.USE_RSRP); + sDefaults.putBoolean(KEY_REMOVE_SATELLITE_PLMN_IN_MANUAL_NETWORK_SCAN_BOOL, true); sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); sDefaults.putBoolean(KEY_SUPPORTS_CALL_COMPOSER_BOOL, false); @@ -10955,6 +10967,9 @@ public class CarrierConfigManager { * @return A {@link PersistableBundle} containing the config for the given subId, or default * values for an invalid subId. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. + * * @deprecated Use {@link #getConfigForSubId(int, String...)} instead. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @@ -11002,6 +11017,9 @@ public class CarrierConfigManager { * @return A {@link PersistableBundle} with key/value mapping for the specified configuration * on success, or an empty (but never null) bundle on failure (for example, when the calling app * has no permission). + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(anyOf = { Manifest.permission.READ_PHONE_STATE, @@ -11047,6 +11065,9 @@ public class CarrierConfigManager { * @param overrideValues Key-value pairs of the values that are to be overridden. If set to * {@code null}, this will remove all previous overrides and set the * carrier configuration back to production values. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) @@ -11104,6 +11125,10 @@ public class CarrierConfigManager { * * @see #getConfigForSubId * @see #getConfig(String...) + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. + * * @deprecated use {@link #getConfig(String...)} instead. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @@ -11138,6 +11163,9 @@ public class CarrierConfigManager { * configs on success, or an empty (but never null) bundle on failure. * @see #getConfigForSubId(int, String...) * @see SubscriptionManager#getDefaultSubscriptionId() + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @RequiresPermission(anyOf = { Manifest.permission.READ_PHONE_STATE, @@ -11189,6 +11217,9 @@ public class CarrierConfigManager { * * <p>This method returns before the reload has completed, and {@link * android.service.carrier.CarrierService#onLoadConfig} will be called from an arbitrary thread. + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -11212,6 +11243,8 @@ public class CarrierConfigManager { * <p>Depending on simState, the config may be cleared or loaded from config app. This is only * used by SubscriptionInfoUpdater. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @SystemApi @@ -11234,6 +11267,8 @@ public class CarrierConfigManager { * Gets the package name for a default carrier service. * @return the package name for a default carrier service; empty string if not available. * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. * @hide */ @NonNull @@ -11287,6 +11322,9 @@ public class CarrierConfigManager { * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}. * * @see #getConfigForSubId + * + * @throws UnsupportedOperationException If the device does not have + * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(Manifest.permission.READ_PHONE_STATE) diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 56156024fbab..a5c6d57aed82 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1315,7 +1315,7 @@ public class SubscriptionManager { * A source of phone number: the EF-MSISDN (see 3GPP TS 31.102), * or EF-MDN for CDMA (see 3GPP2 C.P0065-B), from UICC application. * - * <p>The availability and a of the number depends on the carrier. + * <p>The availability and accuracy of the number depends on the carrier. * The number may be updated by over-the-air update to UICC applications * from the carrier, or by other means with physical access to the SIM. */ @@ -1557,12 +1557,21 @@ public class SubscriptionManager { * caller can see all subscription across user profiles as it does today today even if it's * {@code false}. */ - private boolean mIsForAllUserProfiles = false; + private final boolean mIsForAllUserProfiles; /** @hide */ @UnsupportedAppUsage public SubscriptionManager(Context context) { - if (DBG) logd("SubscriptionManager created"); + this(context, false /*isForAllUserProfiles*/); + } + + /** Constructor */ + private SubscriptionManager(Context context, boolean isForAllUserProfiles) { + if (DBG) { + logd("SubscriptionManager created " + + (isForAllUserProfiles ? "for all user profile" : "")); + } + mIsForAllUserProfiles = isForAllUserProfiles; mContext = context; } @@ -1998,7 +2007,7 @@ public class SubscriptionManager { } /** - * Convert this subscription manager instance into one that can see all subscriptions across + * Create a new subscription manager instance that can see all subscriptions across * user profiles. * * @return a SubscriptionManager that can see all subscriptions regardless its user profile @@ -2008,13 +2017,12 @@ public class SubscriptionManager { * @see #getActiveSubscriptionInfoCount * @see UserHandle */ - @FlaggedApi(Flags.FLAG_WORK_PROFILE_API_SPLIT) + @FlaggedApi(Flags.FLAG_ENFORCE_SUBSCRIPTION_USER_FILTER) // @RequiresPermission(TODO(b/308809058)) // The permission check for accessing all subscriptions will be enforced upon calling the // individual APIs linked above. @NonNull public SubscriptionManager createForAllUserProfiles() { - mIsForAllUserProfiles = true; - return this; + return new SubscriptionManager(mContext, true/*isForAllUserProfiles*/); } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1b47dfe0eba1..e4ea479fb4d6 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -6445,10 +6445,6 @@ public class TelephonyManager { * targeting API level 31+. * * @return the current call state. - * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELECOM}. - * * @deprecated Use {@link #getCallStateForSubscription} to retrieve the call state for a * specific telephony subscription (which allows carrier privileged apps), * {@link TelephonyCallback.CallStateListener} for real-time call state updates, or @@ -6456,7 +6452,6 @@ public class TelephonyManager { * device. */ @RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true) - @RequiresFeature(PackageManager.FEATURE_TELECOM) @Deprecated public @CallState int getCallState() { if (mContext != null) { @@ -10782,9 +10777,7 @@ public class TelephonyManager { } /** - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELECOM}. - * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead + * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead * @hide */ @Deprecated @@ -10793,15 +10786,12 @@ public class TelephonyManager { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE }) - @RequiresFeature(PackageManager.FEATURE_TELECOM) public boolean isOffhook() { TelecomManager tm = (TelecomManager) mContext.getSystemService(TELECOM_SERVICE); return tm.isInCall(); } /** - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELECOM}. * @deprecated Use {@link android.telecom.TelecomManager#isRinging} instead * @hide */ @@ -10811,15 +10801,12 @@ public class TelephonyManager { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE }) - @RequiresFeature(PackageManager.FEATURE_TELECOM) public boolean isRinging() { TelecomManager tm = (TelecomManager) mContext.getSystemService(TELECOM_SERVICE); return tm.isRinging(); } /** - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELECOM}. * @deprecated Use {@link android.telecom.TelecomManager#isInCall} instead * @hide */ @@ -10829,7 +10816,6 @@ public class TelephonyManager { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE }) - @RequiresFeature(PackageManager.FEATURE_TELECOM) public boolean isIdle() { TelecomManager tm = (TelecomManager) mContext.getSystemService(TELECOM_SERVICE); return !tm.isInCall(); @@ -12044,11 +12030,8 @@ public class TelephonyManager { * * @return {@code true} if the device supports TTY mode, and {@code false} otherwise. * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELECOM}. */ @Deprecated - @RequiresFeature(PackageManager.FEATURE_TELECOM) public boolean isTtyModeSupported() { try { TelecomManager telecomManager = null; @@ -18923,6 +18906,62 @@ public class TelephonyManager { } /** + * Enables or disables notifications sent when cellular null cipher or integrity algorithms + * are in use by the cellular modem. + * + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support reporting on ciphering + * and integrity algorithms in use + * @hide + */ + @FlaggedApi(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY) + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi + public void setEnableNullCipherNotifications(boolean enable) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.setEnableNullCipherNotifications(enable); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "setEnableNullCipherNotifications RemoteException", ex); + ex.rethrowFromSystemServer(); + } + } + + /** + * Get whether notifications are enabled for null cipher or integrity algorithms in use by the + * cellular modem. + * + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support reporting on ciphering + * and integrity algorithms in use + * @hide + */ + @FlaggedApi(Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY) + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi + public boolean isNullCipherNotificationsEnabled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isNullCipherNotificationsEnabled(); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Rlog.e(TAG, "isNullCipherNotificationsEnabled RemoteException", ex); + ex.rethrowFromSystemServer(); + } + return false; + } + + + /** * Get current cell broadcast message identifier ranges. * * @throws SecurityException if the caller does not have the required permission diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index 9dd83d1438e2..b6f9e1f4c3af 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -451,7 +451,7 @@ public final class DataCallResponse implements Parcelable { /** * Return the network validation status that was initiated by {@link - * DataService.DataServiceProvider#requestValidation} + * DataService.DataServiceProvider#requestNetworkValidation} * * @return The network validation status of data connection. */ @@ -931,7 +931,7 @@ public final class DataCallResponse implements Parcelable { /** * Set the network validation status that corresponds to the state of the network validation - * request started by {@link DataService.DataServiceProvider#requestValidation} + * request started by {@link DataService.DataServiceProvider#requestNetworkValidation} * * @param status The network validation status. * @return The same instance of the builder. diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 80e91a330185..f04e1c9b221d 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -415,13 +415,13 @@ public abstract class DataService extends Service { * request validation to the DataService and checks if the request has been submitted. */ @FlaggedApi(Flags.FLAG_NETWORK_VALIDATION) - public void requestValidation(int cid, + public void requestNetworkValidation(int cid, @NonNull @CallbackExecutor Executor executor, @NonNull @DataServiceCallback.ResultCode Consumer<Integer> resultCodeCallback) { Objects.requireNonNull(executor, "executor cannot be null"); Objects.requireNonNull(resultCodeCallback, "resultCodeCallback cannot be null"); - Log.d(TAG, "requestValidation: " + cid); + Log.d(TAG, "requestNetworkValidation: " + cid); // The default implementation is to return unsupported. executor.execute(() -> resultCodeCallback @@ -741,7 +741,7 @@ public abstract class DataService extends Service { case DATA_SERVICE_REQUEST_VALIDATION: if (serviceProvider == null) break; ValidationRequest validationRequest = (ValidationRequest) message.obj; - serviceProvider.requestValidation( + serviceProvider.requestNetworkValidation( validationRequest.cid, validationRequest.executor, FunctionalUtils @@ -924,9 +924,10 @@ public abstract class DataService extends Service { } @Override - public void requestValidation(int slotIndex, int cid, IIntegerConsumer resultCodeCallback) { + public void requestNetworkValidation(int slotIndex, int cid, + IIntegerConsumer resultCodeCallback) { if (resultCodeCallback == null) { - loge("requestValidation: resultCodeCallback is null"); + loge("requestNetworkValidation: resultCodeCallback is null"); return; } ValidationRequest validationRequest = diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index 15f88815ec6b..c36c302ee986 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -48,5 +48,5 @@ oneway interface IDataService void cancelHandover(int slotId, int cid, IDataServiceCallback callback); void registerForUnthrottleApn(int slotIndex, IDataServiceCallback callback); void unregisterForUnthrottleApn(int slotIndex, IDataServiceCallback callback); - void requestValidation(int slotId, int cid, IIntegerConsumer callback); + void requestNetworkValidation(int slotId, int cid, IIntegerConsumer callback); } diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 54ceaed617ec..9f83da930221 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -84,7 +84,7 @@ public interface RegistrationManager { SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK, SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT, SUGGESTED_ACTION_TRIGGER_RAT_BLOCK, - SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK + SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS }) @Retention(RetentionPolicy.SOURCE) public @interface SuggestedAction {} @@ -116,9 +116,10 @@ public interface RegistrationManager { /** * Indicates that the IMS registration on current RAT failed multiple times. - * The radio shall block the current RAT and search for other available RATs in the - * background. If no other RAT is available that meets the carrier requirements, the - * radio may remain on the current RAT for internet service. The radio clears all + * The radio shall block the {@link ImsRegistrationImplBase.ImsRegistrationTech} + * included with this and search for other available RATs in the background. + * If no other RAT is available that meets the carrier requirements, the + * radio may remain on the blocked RAT for internet service. The radio clears all * RATs marked as unavailable if the IMS service is registered to the carrier network. * @hide */ @@ -133,7 +134,7 @@ public interface RegistrationManager { */ @SystemApi @FlaggedApi(Flags.FLAG_ADD_RAT_RELATED_SUGGESTED_ACTION_TO_IMS_REGISTRATION) - int SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCK = 4; + int SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS = 4; /**@hide*/ // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN diff --git a/telephony/java/android/telephony/satellite/AntennaPosition.java b/telephony/java/android/telephony/satellite/AntennaPosition.java index 8842886d3a1c..d6440fc7a119 100644 --- a/telephony/java/android/telephony/satellite/AntennaPosition.java +++ b/telephony/java/android/telephony/satellite/AntennaPosition.java @@ -35,10 +35,10 @@ import java.util.Objects; @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) public final class AntennaPosition implements Parcelable { /** Antenna direction used for satellite communication. */ - @NonNull AntennaDirection mAntennaDirection; + @NonNull private AntennaDirection mAntennaDirection; /** Enum corresponding to device hold position to be used by the end user. */ - @SatelliteManager.DeviceHoldPosition int mSuggestedHoldPosition; + @SatelliteManager.DeviceHoldPosition private int mSuggestedHoldPosition; /** * @hide diff --git a/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl b/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl index cd9d81e1ee9b..9ff73e2c2f12 100644 --- a/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl +++ b/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl @@ -20,7 +20,7 @@ package android.telephony.satellite; * Interface for satellite state change callback. * @hide */ -oneway interface ISatelliteStateCallback { +oneway interface ISatelliteModemStateCallback { /** * Indicates that the satellite modem state has changed. * diff --git a/telephony/java/android/telephony/satellite/PointingInfo.java b/telephony/java/android/telephony/satellite/PointingInfo.java index 022a856e48dd..9440b65a61aa 100644 --- a/telephony/java/android/telephony/satellite/PointingInfo.java +++ b/telephony/java/android/telephony/satellite/PointingInfo.java @@ -17,6 +17,7 @@ package android.telephony.satellite; import android.annotation.FlaggedApi; +import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; @@ -108,11 +109,19 @@ public final class PointingInfo implements Parcelable { return sb.toString(); } + /** + * Returns the azimuth of the satellite, in degrees. + */ + @FloatRange(from = -180, to = 180) @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) public float getSatelliteAzimuthDegrees() { return mSatelliteAzimuthDegrees; } + /** + * Returns the elevation of the satellite, in degrees. + */ + @FloatRange(from = -90, to = 90) @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) public float getSatelliteElevationDegrees() { return mSatelliteElevationDegrees; diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java index b5763c38e69c..8e79ca5cf3d3 100644 --- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java @@ -22,10 +22,15 @@ import android.annotation.SystemApi; import com.android.internal.telephony.flags.Flags; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** * A callback class for listening to satellite datagrams. + * {@link SatelliteDatagramCallback} is registered to telephony when an app which invokes + * {@link SatelliteManager#registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)}, + * and {@link #onSatelliteDatagramReceived(long, SatelliteDatagram, int, Consumer)} will be invoked + * when a new datagram is received from satellite. * * @hide */ diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index e09bd201f93e..3b0397b6e480 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -49,8 +49,10 @@ import com.android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -75,8 +77,9 @@ public final class SatelliteManager { private static final ConcurrentHashMap<SatelliteProvisionStateCallback, ISatelliteProvisionStateCallback> sSatelliteProvisionStateCallbackMap = new ConcurrentHashMap<>(); - private static final ConcurrentHashMap<SatelliteStateCallback, ISatelliteStateCallback> - sSatelliteStateCallbackMap = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap<SatelliteModemStateCallback, + ISatelliteModemStateCallback> + sSatelliteModemStateCallbackMap = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<SatelliteTransmissionUpdateCallback, ISatelliteTransmissionUpdateCallback> sSatelliteTransmissionUpdateCallbackMap = new ConcurrentHashMap<>(); @@ -624,6 +627,11 @@ public final class SatelliteManager { /** * Request to get whether the satellite service is supported on the device. * + * <p> + * Note: This API only checks whether the device supports the satellite feature. The result will + * not be affected by whether the device is provisioned. + * </p> + * * @param executor The executor on which the callback will be called. * @param callback The callback object to which the result will be delivered. * If the request is successful, {@link OutcomeReceiver#onResult(Object)} @@ -1301,21 +1309,22 @@ public final class SatelliteManager { @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) @SatelliteResult public int registerForSatelliteModemStateChanged( @NonNull @CallbackExecutor Executor executor, - @NonNull SatelliteStateCallback callback) { + @NonNull SatelliteModemStateCallback callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); try { ITelephony telephony = getITelephony(); if (telephony != null) { - ISatelliteStateCallback internalCallback = new ISatelliteStateCallback.Stub() { + ISatelliteModemStateCallback internalCallback = + new ISatelliteModemStateCallback.Stub() { @Override public void onSatelliteModemStateChanged(int state) { executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onSatelliteModemStateChanged(state))); } }; - sSatelliteStateCallbackMap.put(callback, internalCallback); + sSatelliteModemStateCallbackMap.put(callback, internalCallback); return telephony.registerForSatelliteModemStateChanged(mSubId, internalCallback); } else { throw new IllegalStateException("telephony service is null."); @@ -1332,16 +1341,18 @@ public final class SatelliteManager { * If callback was not registered before, the request will be ignored. * * @param callback The callback that was passed to - * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteStateCallback)}. + * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteModemStateCallback)}. * * @throws SecurityException if the caller doesn't have required permission. * @throws IllegalStateException if the Telephony process is not currently available. */ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) - public void unregisterForSatelliteModemStateChanged(@NonNull SatelliteStateCallback callback) { + public void unregisterForSatelliteModemStateChanged( + @NonNull SatelliteModemStateCallback callback) { Objects.requireNonNull(callback); - ISatelliteStateCallback internalCallback = sSatelliteStateCallbackMap.remove(callback); + ISatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackMap.remove( + callback); try { ITelephony telephony = getITelephony(); @@ -2133,6 +2144,35 @@ public final class SatelliteManager { } } + /** + * Get all satellite PLMNs for which attach is enable for carrier. + * + * @param subId subId The subscription ID of the carrier. + * + * @return List of plmn for carrier satellite service. If no plmn is available, empty list will + * be returned. + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + @FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) + @NonNull public List<String> getAllSatellitePlmnsForCarrier(int subId) { + if (!SubscriptionManager.isValidSubscriptionId(subId)) { + throw new IllegalArgumentException("Invalid subscription ID"); + } + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getAllSatellitePlmnsForCarrier(subId); + } else { + throw new IllegalStateException("Telephony service is null."); + } + } catch (RemoteException ex) { + loge("getAllSatellitePlmnsForCarrier() RemoteException: " + ex); + ex.rethrowFromSystemServer(); + } + return new ArrayList<>(); + } + private static ITelephony getITelephony() { ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer .getTelephonyServiceManager() diff --git a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java b/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java index bfe6e101ffb4..8d33c88136a6 100644 --- a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java +++ b/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java @@ -28,7 +28,7 @@ import com.android.internal.telephony.flags.Flags; */ @SystemApi @FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) -public interface SatelliteStateCallback { +public interface SatelliteModemStateCallback { /** * Called when satellite modem state changes. * @param state The new satellite modem state. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 9b5ee0cd82f3..acbf354bb4de 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -72,7 +72,7 @@ import android.telephony.satellite.ISatelliteCapabilitiesCallback; import android.telephony.satellite.ISatelliteDatagramCallback; import android.telephony.satellite.ISatelliteTransmissionUpdateCallback; import android.telephony.satellite.ISatelliteProvisionStateCallback; -import android.telephony.satellite.ISatelliteStateCallback; +import android.telephony.satellite.ISatelliteModemStateCallback; import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteCapabilities; import android.telephony.satellite.SatelliteDatagram; @@ -2896,7 +2896,7 @@ interface ITelephony { */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + "android.Manifest.permission.SATELLITE_COMMUNICATION)") - int registerForSatelliteModemStateChanged(int subId, ISatelliteStateCallback callback); + int registerForSatelliteModemStateChanged(int subId, ISatelliteModemStateCallback callback); /** * Unregisters for modem state changed from satellite modem. @@ -2907,7 +2907,7 @@ interface ITelephony { */ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + "android.Manifest.permission.SATELLITE_COMMUNICATION)") - void unregisterForSatelliteModemStateChanged(int subId, ISatelliteStateCallback callback); + void unregisterForSatelliteModemStateChanged(int subId, ISatelliteModemStateCallback callback); /** * Register to receive incoming datagrams over satellite. @@ -3230,4 +3230,45 @@ interface ITelephony { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") boolean isCellularIdentifierDisclosureNotificationsEnabled(); + + /** + * Enables or disables notifications sent when cellular null cipher or integrity algorithms + * are in use by the cellular modem. + * + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support reporting on ciphering + * and integrity algorithms in use + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.MODIFY_PHONE_STATE)") + void setEnableNullCipherNotifications(boolean enable); + + /** + * Get whether notifications are enabled for null cipher or integrity algorithms in use by the + * cellular modem. + * + * @throws IllegalStateException if the Telephony process is not currently available + * @throws SecurityException if the caller does not have the required privileges + * @throws UnsupportedOperationException if the modem does not support reporting on ciphering + * and integrity algorithms in use + * @hide + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)") + boolean isNullCipherNotificationsEnabled(); + + /** + * Get the aggregated satellite plmn list. This API collects plmn data from multiple sources, + * including carrier config, entitlement server, and config update. + * + * @param subId subId The subscription ID of the carrier. + * + * @return List of plmns for carrier satellite service. If no plmn is available, empty list will + * be returned. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + List<String> getAllSatellitePlmnsForCarrier(int subId); } diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java index 80c1e5be3a32..217659ee4345 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java @@ -43,9 +43,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; /** @@ -178,8 +176,14 @@ public class GraphicsActivity extends Activity { this.deviceFrameRate = deviceFrameRate; } + FrameRateTimeoutException(List<Float> expectedFrameRates, float deviceFrameRate) { + this.expectedFrameRates = expectedFrameRates; + this.deviceFrameRate = deviceFrameRate; + } + public float expectedFrameRate; public float deviceFrameRate; + public List<Float> expectedFrameRates; } public enum Api { @@ -502,31 +506,37 @@ public class GraphicsActivity extends Activity { } private void waitForStableFrameRate(TestSurface... surfaces) throws InterruptedException { - verifyCompatibleAndStableFrameRate(0, surfaces); + verifyFrameRates(List.of(), surfaces); } private void verifyExactAndStableFrameRate( float expectedFrameRate, TestSurface... surfaces) throws InterruptedException { - verifyFrameRate(expectedFrameRate, false, surfaces); + verifyFrameRate(List.of(expectedFrameRate), false, surfaces); } private void verifyCompatibleAndStableFrameRate( float expectedFrameRate, TestSurface... surfaces) throws InterruptedException { - verifyFrameRate(expectedFrameRate, true, surfaces); + verifyFrameRate(List.of(expectedFrameRate), true, surfaces); + } + + /** Verify stable frame rate at one of the expectedFrameRates. */ + private void verifyFrameRates(List<Float> expectedFrameRates, TestSurface... surfaces) + throws InterruptedException { + verifyFrameRate(expectedFrameRates, true, surfaces); } - // Set expectedFrameRate to 0.0 to verify only stable frame rate. - private void verifyFrameRate( - float expectedFrameRate, boolean multiplesAllowed, + // Set expectedFrameRates to empty to verify only stable frame rate. + private void verifyFrameRate(List<Float> expectedFrameRates, boolean multiplesAllowed, TestSurface... surfaces) throws InterruptedException { Log.i(TAG, "Verifying compatible and stable frame rate"); long nowNanos = System.nanoTime(); long gracePeriodEndTimeNanos = nowNanos + FRAME_RATE_SWITCH_GRACE_PERIOD_SECONDS * 1_000_000_000L; while (true) { - if (expectedFrameRate > FRAME_RATE_TOLERANCE) { // expectedFrameRate > 0 + if (expectedFrameRates.size() == 1) { + float expectedFrameRate = expectedFrameRates.get(0); // Wait until we switch to a compatible frame rate. Log.i(TAG, String.format( @@ -557,11 +567,25 @@ public class GraphicsActivity extends Activity { while (endTimeNanos > nowNanos) { int numModeChangedEvents = mModeChangedEvents.size(); if (waitForEvents(endTimeNanos, surfaces)) { - Log.i(TAG, - String.format("Stable frame rate %.2f verified", - multiplesAllowed ? mDisplayModeRefreshRate - : mDisplayRefreshRate)); - return; + // Verify any expected frame rate since there are multiple that will suffice. + // Mainly to account for running tests on real devices, where other non-test + // layers may affect the outcome. + if (expectedFrameRates.size() > 1) { + for (float expectedFrameRate : expectedFrameRates) { + if (isFrameRateMultiple(mDisplayModeRefreshRate, expectedFrameRate)) { + return; + } + } + // The frame rate is stable but it is not one of the expected frame rates. + throw new FrameRateTimeoutException( + expectedFrameRates, mDisplayModeRefreshRate); + } else { + Log.i(TAG, + String.format("Stable frame rate %.2f verified", + multiplesAllowed ? mDisplayModeRefreshRate + : mDisplayRefreshRate)); + return; + } } nowNanos = System.nanoTime(); if (mModeChangedEvents.size() > numModeChangedEvents) { @@ -623,12 +647,28 @@ public class GraphicsActivity extends Activity { // caused the timeout failure. Wait for a bit to see if we get notified // of a precondition violation, and if so, retry the test. Otherwise // fail. - assertTrue(String.format( - "Timed out waiting for a stable and compatible frame" - + " rate. expected=%.2f received=%.2f." - + " Stack trace: " + stackTrace, - exc.expectedFrameRate, exc.deviceFrameRate), - waitForPreconditionViolation()); + if (exc.expectedFrameRates.isEmpty()) { + assertTrue( + String.format( + "Timed out waiting for a stable and compatible" + + " frame rate." + + " expected=%.2f received=%.2f." + + " Stack trace: " + stackTrace, + exc.expectedFrameRate, exc.deviceFrameRate), + waitForPreconditionViolation()); + } else { + assertTrue( + String.format( + "Timed out waiting for a stable and compatible" + + " frame rate." + + " expected={%.2f} received=%.2f." + + " Stack trace: " + stackTrace, + exc.expectedFrameRates.stream() + .map(Object::toString) + .collect(Collectors.joining(", ")), + exc.deviceFrameRate), + waitForPreconditionViolation()); + } } if (!testPassed) { @@ -679,10 +719,15 @@ public class GraphicsActivity extends Activity { "**** Running testSurfaceControlFrameRateCompatibility with compatibility " + compatibility); - float expectedFrameRate = getExpectedFrameRateForCompatibility(compatibility); + List<Float> expectedFrameRates = getExpectedFrameRateForCompatibility(compatibility); + Log.i(TAG, + "Expected frame rates: " + + expectedFrameRates.stream() + .map(Object::toString) + .collect(Collectors.joining(", "))); int initialNumEvents = mModeChangedEvents.size(); surface.setFrameRate(30.f, compatibility); - verifyExactAndStableFrameRate(expectedFrameRate, surface); + verifyFrameRates(expectedFrameRates, surface); verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size()); }); } @@ -699,10 +744,10 @@ public class GraphicsActivity extends Activity { runOneSurfaceTest((TestSurface surface) -> { Log.i(TAG, "**** Running testSurfaceControlFrameRateCategory for category " + category); - float expectedFrameRate = getExpectedFrameRateForCategory(category); + List<Float> expectedFrameRates = getExpectedFrameRateForCategory(category); int initialNumEvents = mModeChangedEvents.size(); surface.setFrameRateCategory(category); - verifyCompatibleAndStableFrameRate(expectedFrameRate, surface); + verifyFrameRates(expectedFrameRates, surface); verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size()); }); } @@ -771,41 +816,41 @@ public class GraphicsActivity extends Activity { "frame rate strategy=" + parentStrategy); } - private float getExpectedFrameRateForCompatibility(int compatibility) { + private List<Float> getExpectedFrameRateForCompatibility(int compatibility) { assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED for compatibility " + compatibility, compatibility == Surface.FRAME_RATE_COMPATIBILITY_GTE); Display display = getDisplay(); - Optional<Float> expectedFrameRate = getRefreshRates(display.getMode(), display) - .stream() - .filter(rate -> rate >= 30.f) - .min(Comparator.naturalOrder()); + List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display) + .stream() + .filter(rate -> rate >= 30.f) + .collect(Collectors.toList()); assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED because no refresh rate " + "is >= 30", - expectedFrameRate.isPresent()); - return expectedFrameRate.get(); + !expectedFrameRates.isEmpty()); + return expectedFrameRates; } - private float getExpectedFrameRateForCategory(int category) { + private List<Float> getExpectedFrameRateForCategory(int category) { Display display = getDisplay(); List<Float> frameRates = getRefreshRates(display.getMode(), display); if (category == Surface.FRAME_RATE_CATEGORY_DEFAULT) { // Max due to default vote and no other frame rate specifications. - return Collections.max(frameRates); + return List.of(Collections.max(frameRates)); } else if (category == Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE) { - return Collections.min(frameRates); + return frameRates; } FpsRange categoryRange = convertCategory(category); - Optional<Float> expectedFrameRate = frameRates.stream() - .filter(fps -> categoryRange.includes(fps)) - .min(Comparator.naturalOrder()); + List<Float> expectedFrameRates = frameRates.stream() + .filter(fps -> categoryRange.includes(fps)) + .collect(Collectors.toList()); assumeTrue("**** testSurfaceControlFrameRateCategory SKIPPED for category " + category, - expectedFrameRate.isPresent()); - return expectedFrameRate.get(); + !expectedFrameRates.isEmpty()); + return expectedFrameRates; } private FpsRange convertCategory(int category) { diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java index 29cbf01dc6da..e3988cd20199 100644 --- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java +++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java @@ -24,8 +24,8 @@ import android.os.Bundle; import android.view.View; import android.widget.ToggleButton; +import androidx.window.embedding.ActivityEmbeddingController; import androidx.window.embedding.SplitAttributes; -import androidx.window.embedding.SplitAttributesCalculatorParams; import androidx.window.embedding.SplitController; /** @@ -66,7 +66,9 @@ public class ActivityEmbeddingSecondaryActivity extends Activity { @Override public void onClick(View v) { // This triggers a recalcuation of splitatributes. - mSplitController.invalidateTopVisibleSplitAttributes(); + ActivityEmbeddingController + .getInstance(ActivityEmbeddingSecondaryActivity.this) + .invalidateTopVisibleActivityStacks(); } }); findViewById(R.id.secondary_enter_pip_button).setOnClickListener( diff --git a/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java index be479f205ff2..1b0279273dc7 100644 --- a/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java +++ b/tests/FsVerityTest/src/com/android/fsverity/FsVerityHostTest.java @@ -25,6 +25,7 @@ import android.platform.test.flag.junit.host.HostFlagsValueProvider; import android.security.Flags; import com.android.blockdevicewriter.BlockDeviceWriter; +import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -52,7 +53,6 @@ public class FsVerityHostTest extends BaseHostJUnit4Test { private static final String TARGET_PACKAGE = "com.android.fsverity"; private static final String BASENAME = "test.file"; - private static final String TARGET_PATH = "/data/data/" + TARGET_PACKAGE + "/files/" + BASENAME; @Rule public final CheckFlagsRule mCheckFlagsRule = @@ -63,11 +63,11 @@ public class FsVerityHostTest extends BaseHostJUnit4Test { prepareTest(10000); ITestDevice device = getDevice(); - BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 0); - BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 8192); + BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 0); + BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 8192); BlockDeviceWriter.dropCaches(device); - verifyRead(TARGET_PATH, "0,2"); + verifyRead(getTargetFilePath(), "0,2"); } @Test @@ -75,12 +75,17 @@ public class FsVerityHostTest extends BaseHostJUnit4Test { prepareTest(128 * 4096 + 1); ITestDevice device = getDevice(); - BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 4096); - BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 100 * 4096); - BlockDeviceWriter.damageFileAgainstBlockDevice(device, TARGET_PATH, 128 * 4096 + 1); + BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 4096); + BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 100 * 4096); + BlockDeviceWriter.damageFileAgainstBlockDevice(device, getTargetFilePath(), 128 * 4096 + 1); BlockDeviceWriter.dropCaches(device); - verifyRead(TARGET_PATH, "1,100,128"); + verifyRead(getTargetFilePath(), "1,100,128"); + } + + private String getTargetFilePath() throws DeviceNotAvailableException { + return "/data/user/" + getDevice().getCurrentUser() + "/" + TARGET_PACKAGE + "/files/" + + BASENAME; } private void prepareTest(int fileSize) throws Exception { @@ -97,7 +102,7 @@ public class FsVerityHostTest extends BaseHostJUnit4Test { options.setTestClassName(TARGET_PACKAGE + ".Helper"); options.setTestMethodName("verifyFileRead"); options.addInstrumentationArg("brokenBlockIndicesCsv", indicesCsv); - options.addInstrumentationArg("filePath", TARGET_PATH); + options.addInstrumentationArg("filePath", getTargetFilePath()); assertThat(runDeviceTests(options)).isTrue(); } } diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt index c1784f3b42e7..7b191f8388c5 100644 --- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt +++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt @@ -22,7 +22,6 @@ import android.content.ContextWrapper import android.hardware.display.DisplayViewport import android.hardware.input.InputManager import android.hardware.input.InputManagerGlobal -import android.os.IInputConstants import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.provider.Settings @@ -295,14 +294,13 @@ class InputManagerServiceTests { localService.setPointerIconVisible(false, 10) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL)) - localService.setPointerAcceleration(5f, 10) - verify(native).setPointerAcceleration(eq(5f)) + localService.setMousePointerAccelerationEnabled(false, 10) + verify(native).setMousePointerAccelerationEnabled(eq(false)) service.onDisplayRemoved(10) verify(native).displayRemoved(eq(10)) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NOT_SPECIFIED)) - verify(native).setPointerAcceleration( - eq(IInputConstants.DEFAULT_POINTER_ACCELERATION.toFloat())) + verify(native).setMousePointerAccelerationEnabled(true) verifyNoMoreInteractions(native) // This call should not block because the virtual mouse pointer override was never removed. @@ -318,38 +316,38 @@ class InputManagerServiceTests { localService.setPointerIconVisible(false, 10) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL)) - localService.setPointerAcceleration(5f, 10) - verify(native).setPointerAcceleration(eq(5f)) + localService.setMousePointerAccelerationEnabled(false, 10) + verify(native).setMousePointerAccelerationEnabled(eq(false)) localService.setPointerIconVisible(true, 10) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NOT_SPECIFIED)) - localService.setPointerAcceleration(1f, 10) - verify(native).setPointerAcceleration(eq(1f)) + localService.setMousePointerAccelerationEnabled(true, 10) + verify(native).setMousePointerAccelerationEnabled(eq(true)) // Verify that setting properties on a different display is not propagated until the // pointer is moved to that display. localService.setPointerIconVisible(false, 20) - localService.setPointerAcceleration(6f, 20) + localService.setMousePointerAccelerationEnabled(false, 20) verifyNoMoreInteractions(native) clearInvocations(native) setVirtualMousePointerDisplayIdAndVerify(20) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL)) - verify(native).setPointerAcceleration(eq(6f)) + verify(native).setMousePointerAccelerationEnabled(eq(false)) } @Test fun setAdditionalInputPropertiesBeforeOverride() { localService.setPointerIconVisible(false, 10) - localService.setPointerAcceleration(5f, 10) + localService.setMousePointerAccelerationEnabled(false, 10) verifyNoMoreInteractions(native) setVirtualMousePointerDisplayIdAndVerify(10) verify(native).setPointerIconType(eq(PointerIcon.TYPE_NULL)) - verify(native).setPointerAcceleration(eq(5f)) + verify(native).setMousePointerAccelerationEnabled(eq(false)) } @Test diff --git a/tests/SurfaceControlViewHostTest/AndroidManifest.xml b/tests/SurfaceControlViewHostTest/AndroidManifest.xml index e50cbc52a5b8..71f01ac5ded1 100644 --- a/tests/SurfaceControlViewHostTest/AndroidManifest.xml +++ b/tests/SurfaceControlViewHostTest/AndroidManifest.xml @@ -32,6 +32,16 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + + <activity android:name="SurfaceInputTestActivity" + android:label="Surface Input Test" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + <service android:name=".EmbeddedWindowService" android:process="com.android.test.viewembed.embedded_process"/> </application> diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java index abc15b49ad98..5aaf30a5b3a7 100644 --- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java +++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java @@ -23,15 +23,21 @@ import android.annotation.Nullable; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Paint; import android.graphics.PixelFormat; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.util.Log; +import android.view.Choreographer; import android.view.Display; import android.view.Gravity; +import android.view.Surface; +import android.view.SurfaceControl; import android.view.SurfaceControlViewHost; import android.view.WindowManager; import android.widget.FrameLayout; @@ -43,6 +49,9 @@ public class EmbeddedWindowService extends Service { private Handler mHandler; + private IBinder mInputToken; + private SurfaceControl mSurfaceControl; + @Override public void onCreate() { super.onCreate(); @@ -101,9 +110,49 @@ public class EmbeddedWindowService extends Service { } }); } + @Override public void relayout(WindowManager.LayoutParams lp) { mHandler.post(() -> mVr.relayout(lp)); } + + @Override + public void attachEmbeddedSurfaceControl(SurfaceControl parentSc, int displayId, + IBinder hostToken) { + mHandler.post(() -> { + Paint paint = new Paint(); + paint.setTextSize(40); + paint.setColor(Color.WHITE); + + mSurfaceControl = new SurfaceControl.Builder().setName("Child SurfaceControl") + .setParent(parentSc).setBufferSize(500, 500).build(); + new SurfaceControl.Transaction().show(mSurfaceControl).apply(); + + Surface surface = new Surface(mSurfaceControl); + Canvas c = surface.lockCanvas(null); + c.drawColor(Color.BLUE); + c.drawText("Remote", 250, 250, paint); + surface.unlockCanvasAndPost(c); + WindowManager wm = getSystemService(WindowManager.class); + mInputToken = wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken, + mSurfaceControl, + Choreographer.getInstance(), event -> { + Log.d(TAG, "onInputEvent-remote " + event); + return false; + }); + + }); + } + + @Override + public void tearDownEmbeddedSurfaceControl() { + if (mSurfaceControl != null) { + new SurfaceControl.Transaction().remove(mSurfaceControl); + } + if (mInputToken != null) { + WindowManager wm = getSystemService(WindowManager.class); + wm.unregisterSurfaceControlInputReceiver(mInputToken); + } + } } } diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl index 9e9faf03ba1c..6b65b40ef8c6 100644 --- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl +++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl @@ -19,8 +19,11 @@ package com.android.test.viewembed; import android.os.IBinder; import com.android.test.viewembed.IAttachEmbeddedWindowCallback; import android.view.WindowManager.LayoutParams; +import android.view.SurfaceControl; interface IAttachEmbeddedWindow { void attachEmbedded(IBinder hostToken, int width, int height, in IAttachEmbeddedWindowCallback callback); void relayout(in LayoutParams lp); + oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId, IBinder hostToken); + oneway void tearDownEmbeddedSurfaceControl(); }
\ No newline at end of file diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java new file mode 100644 index 000000000000..e5f8f47aeecd --- /dev/null +++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java @@ -0,0 +1,217 @@ +/* + * Copyright 2024 The Android Open 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.test.viewembed; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.AttachedSurfaceControl; +import android.view.Choreographer; +import android.view.Gravity; +import android.view.Surface; +import android.view.SurfaceControl; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.ViewTreeObserver; +import android.view.WindowManager; +import android.widget.LinearLayout; + +/** + * Used to manually test that {@link android.view.SurfaceControlInputReceiver} API works. + */ +public class SurfaceInputTestActivity extends Activity { + + private static final String TAG = "SurfaceInputTestActivity"; + private SurfaceView mLocalSurfaceView; + private SurfaceView mRemoteSurfaceView; + private IBinder mInputToken; + private IAttachEmbeddedWindow mIAttachEmbeddedWindow; + private SurfaceControl mParentSurfaceControl; + + private final ServiceConnection mConnection = new ServiceConnection() { + // Called when the connection with the service is established + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "Service Connected"); + mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service); + loadEmbedded(); + } + + public void onServiceDisconnected(ComponentName className) { + Log.d(TAG, "Service Disconnected"); + mIAttachEmbeddedWindow = null; + } + }; + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver(); + viewTreeObserver.addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + addLocalChildSurfaceControl(getWindow().getRootSurfaceControl()); + viewTreeObserver.removeOnPreDrawListener(this); + return true; + } + }); + } + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LinearLayout content = new LinearLayout(this); + mLocalSurfaceView = new SurfaceView(this); + content.addView(mLocalSurfaceView, new LinearLayout.LayoutParams( + 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + mRemoteSurfaceView = new SurfaceView(this); + content.addView(mRemoteSurfaceView, new LinearLayout.LayoutParams( + 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + setContentView(content); + + mLocalSurfaceView.setZOrderOnTop(true); + mLocalSurfaceView.getHolder().addCallback(mLocalSurfaceViewCallback); + + mRemoteSurfaceView.setZOrderOnTop(true); + mRemoteSurfaceView.getHolder().addCallback(mRemoteSurfaceViewHolder); + + Intent intent = new Intent(this, EmbeddedWindowService.class); + intent.setAction(IAttachEmbeddedWindow.class.getName()); + Log.d(TAG, "bindService"); + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken); + } + + private void addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl) { + SurfaceControl surfaceControl = new SurfaceControl.Builder().setName("LocalSC") + .setBufferSize(100, 100).build(); + attachedSurfaceControl.buildReparentTransaction(surfaceControl) + .setVisibility(surfaceControl, true) + .setCrop(surfaceControl, new Rect(0, 0, 100, 100)) + .setPosition(surfaceControl, 250, 1000) + .setLayer(surfaceControl, 1).apply(); + + Paint paint = new Paint(); + paint.setColor(Color.WHITE); + paint.setTextSize(20); + + Surface surface = new Surface(surfaceControl); + Canvas c = surface.lockCanvas(null); + c.drawColor(Color.GREEN); + c.drawText("Local SC", 0, 0, paint); + surface.unlockCanvasAndPost(c); + WindowManager wm = getSystemService(WindowManager.class); + mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(), + attachedSurfaceControl.getHostToken(), surfaceControl, + Choreographer.getInstance(), event -> { + Log.d(TAG, "onInputEvent-sc " + event); + return false; + }); + } + + private final SurfaceHolder.Callback mLocalSurfaceViewCallback = new SurfaceHolder.Callback() { + private IBinder mInputToken; + + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + Paint paint = new Paint(); + paint.setColor(Color.WHITE); + paint.setTextSize(40); + + Canvas c = holder.lockCanvas(); + c.drawColor(Color.RED); + c.drawText("Local", 250, 250, paint); + holder.unlockCanvasAndPost(c); + + WindowManager wm = getSystemService(WindowManager.class); + mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(), + mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(), + Choreographer.getInstance(), event -> { + Log.d(TAG, "onInputEvent-local " + event); + return false; + }); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, + int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + if (mInputToken != null) { + getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken); + } + } + }; + + private final SurfaceHolder.Callback mRemoteSurfaceViewHolder = new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + mParentSurfaceControl = mRemoteSurfaceView.getSurfaceControl(); + loadEmbedded(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, + int height) { + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + if (mIAttachEmbeddedWindow != null) { + try { + mIAttachEmbeddedWindow.tearDownEmbeddedSurfaceControl(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to tear down embedded SurfaceControl", e); + } + } + } + }; + + private void loadEmbedded() { + if (mParentSurfaceControl == null || mIAttachEmbeddedWindow == null) { + return; + } + try { + mIAttachEmbeddedWindow.attachEmbeddedSurfaceControl(mParentSurfaceControl, + getDisplayId(), mRemoteSurfaceView.getHostToken()); + } catch (RemoteException e) { + Log.e(TAG, "Failed to load embedded SurfaceControl", e); + } + } +} diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index f84616426389..20b7f1f14691 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -269,6 +269,7 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection @Test public void testCreatedTransformsAreApplied() throws Exception { verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */); + verify(mUnderlyingNetworkController).updateInboundTransform(any(), any()); } @Test @@ -327,6 +328,8 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } + verify(mUnderlyingNetworkController).updateInboundTransform(any(), any()); + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); final List<ChildSaProposal> saProposals = diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java index 692c8a8f0898..49665f7a3304 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java @@ -27,15 +27,18 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; +import static com.android.server.vcn.VcnGatewayConnection.SAFEMODE_TIMEOUT_SECONDS; import static com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.CALLS_REAL_METHODS; @@ -55,6 +58,7 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.net.vcn.VcnManager; import android.net.vcn.VcnTransportInfo; import android.net.wifi.WifiInfo; import android.os.ParcelUuid; @@ -81,6 +85,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; /** Tests for TelephonySubscriptionTracker */ @RunWith(AndroidJUnit4.class) @@ -352,4 +357,71 @@ public class VcnGatewayConnectionTest extends VcnGatewayConnectionTestBase { any(Executor.class), any(ConnectivityDiagnosticsCallback.class)); } + + private void verifyGetSafeModeTimeoutMs( + boolean isInTestMode, + boolean isConfigTimeoutSupported, + PersistableBundleWrapper carrierConfig, + long expectedTimeoutMs) + throws Exception { + doReturn(isInTestMode).when(mVcnContext).isInTestMode(); + doReturn(isConfigTimeoutSupported).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); + + final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); + doReturn(carrierConfig).when(snapshot).getCarrierConfigForSubGrp(TEST_SUB_GRP); + + final long result = + VcnGatewayConnection.getSafeModeTimeoutMs(mVcnContext, snapshot, TEST_SUB_GRP); + + assertEquals(expectedTimeoutMs, result); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutUnsupported() throws Exception { + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + false /* isConfigTimeoutSupported */, + null /* carrierConfig */, + TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutSupported() throws Exception { + final int carrierConfigTimeoutSeconds = 20; + final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); + doReturn(carrierConfigTimeoutSeconds) + .when(carrierConfig) + .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt()); + + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + true /* isConfigTimeoutSupported */, + carrierConfig, + TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutSupported_carrierConfigNull() + throws Exception { + verifyGetSafeModeTimeoutMs( + false /* isInTestMode */, + true /* isConfigTimeoutSupported */, + null /* carrierConfig */, + TimeUnit.SECONDS.toMillis(SAFEMODE_TIMEOUT_SECONDS)); + } + + @Test + public void testGetSafeModeTimeoutMs_configTimeoutOverrideTestModeDefault() throws Exception { + final int carrierConfigTimeoutSeconds = 20; + final PersistableBundleWrapper carrierConfig = mock(PersistableBundleWrapper.class); + doReturn(carrierConfigTimeoutSeconds) + .when(carrierConfig) + .getInt(eq(VcnManager.VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY), anyInt()); + + verifyGetSafeModeTimeoutMs( + true /* isInTestMode */, + true /* isConfigTimeoutSupported */, + carrierConfig, + TimeUnit.SECONDS.toMillis(carrierConfigTimeoutSeconds)); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index edced87427c8..e29e4621d571 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -67,6 +67,8 @@ import com.android.server.IpSecService; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.Vcn.VcnGatewayStatusCallback; import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback; +import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; +import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent; import com.android.server.vcn.VcnGatewayConnection.VcnWakeLock; import com.android.server.vcn.routeselection.UnderlyingNetworkController; import com.android.server.vcn.routeselection.UnderlyingNetworkRecord; @@ -118,13 +120,7 @@ public class VcnGatewayConnectionTestBase { NetworkCapabilities networkCapabilities, LinkProperties linkProperties, boolean isBlocked) { - return new UnderlyingNetworkRecord( - network, - networkCapabilities, - linkProperties, - isBlocked, - false /* isSelected */, - 0 /* priorityClass */); + return new UnderlyingNetworkRecord(network, networkCapabilities, linkProperties, isBlocked); } protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4"; @@ -226,6 +222,9 @@ public class VcnGatewayConnectionTestBase { doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); + doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); + doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); + doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java new file mode 100644 index 000000000000..9daba6a79a27 --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY; +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY; + +import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +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.BroadcastReceiver; +import android.content.Intent; +import android.net.IpSecTransformState; +import android.os.OutcomeReceiver; +import android.os.PowerManager; + +import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator; +import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper; +import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.Spy; + +import java.util.Arrays; +import java.util.BitSet; +import java.util.concurrent.TimeUnit; + +public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase { + private static final String TAG = IpSecPacketLossDetectorTest.class.getSimpleName(); + + private static final int REPLAY_BITMAP_LEN_BYTE = 512; + private static final int REPLAY_BITMAP_LEN_BIT = REPLAY_BITMAP_LEN_BYTE * 8; + private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD = 5; + private static final long POLL_IPSEC_STATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(30L); + + @Mock private IpSecTransformWrapper mIpSecTransform; + @Mock private NetworkMetricMonitorCallback mMetricMonitorCallback; + @Mock private PersistableBundleWrapper mCarrierConfig; + @Mock private IpSecPacketLossDetector.Dependencies mDependencies; + @Spy private PacketLossCalculator mPacketLossCalculator = new PacketLossCalculator(); + + @Captor private ArgumentCaptor<OutcomeReceiver> mTransformStateReceiverCaptor; + @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor; + + private IpSecPacketLossDetector mIpSecPacketLossDetector; + private IpSecTransformState mTransformStateInitial; + + @Before + public void setUp() throws Exception { + super.setUp(); + mTransformStateInitial = newTransformState(0, 0, newReplayBitmap(0)); + + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt())) + .thenReturn((int) TimeUnit.MILLISECONDS.toSeconds(POLL_IPSEC_STATE_INTERVAL_MS)); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY), + anyInt())) + .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD); + + when(mDependencies.getPacketLossCalculator()).thenReturn(mPacketLossCalculator); + + mIpSecPacketLossDetector = + new IpSecPacketLossDetector( + mVcnContext, + mNetwork, + mCarrierConfig, + mMetricMonitorCallback, + mDependencies); + } + + private static IpSecTransformState newTransformState( + long rxSeqNo, long packtCount, byte[] replayBitmap) { + return new IpSecTransformState.Builder() + .setRxHighestSequenceNumber(rxSeqNo) + .setPacketCount(packtCount) + .setReplayBitmap(replayBitmap) + .build(); + } + + private static byte[] newReplayBitmap(int receivedPktCnt) { + final BitSet bitSet = new BitSet(REPLAY_BITMAP_LEN_BIT); + for (int i = 0; i < receivedPktCnt; i++) { + bitSet.set(i); + } + return Arrays.copyOf(bitSet.toByteArray(), REPLAY_BITMAP_LEN_BYTE); + } + + private void verifyStopped() { + assertFalse(mIpSecPacketLossDetector.isStarted()); + assertFalse(mIpSecPacketLossDetector.isValidationFailed()); + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + + // No event scheduled + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testInitialization() throws Exception { + assertFalse(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork()); + verifyStopped(); + } + + private OutcomeReceiver<IpSecTransformState, RuntimeException> + startMonitorAndCaptureStateReceiver() { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + // Trigger the runnable + mTestLooper.dispatchAll(); + + verify(mIpSecTransform) + .getIpSecTransformState(any(), mTransformStateReceiverCaptor.capture()); + return mTransformStateReceiverCaptor.getValue(); + } + + @Test + public void testStartMonitor() throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertFalse(mIpSecPacketLossDetector.isValidationFailed()); + assertTrue(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork()); + assertEquals(mIpSecTransform, mIpSecPacketLossDetector.getInboundTransformInternal()); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + + // Verify the first polled state is stored + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + + // Verify next poll is scheduled + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNotNull(mTestLooper.nextMessage()); + } + + @Test + public void testStartedMonitor_enterDozeMoze() throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + + // Mock entering doze mode + final Intent intent = mock(Intent.class); + when(intent.getAction()).thenReturn(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); + when(mPowerManagerService.isDeviceIdleMode()).thenReturn(true); + + verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any(), any(), any()); + final BroadcastReceiver broadcastReceiver = mBroadcastReceiverCaptor.getValue(); + broadcastReceiver.onReceive(mContext, intent); + + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + } + + @Test + public void testStartedMonitor_updateInboundTransform() throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + + // Mock receiving a state + xfrmStateReceiver.onResult(mTransformStateInitial); + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + + // Update the inbound transform + final IpSecTransformWrapper newTransform = mock(IpSecTransformWrapper.class); + mIpSecPacketLossDetector.setInboundTransformInternal(newTransform); + + // Verifications + assertNull(mIpSecPacketLossDetector.getLastTransformState()); + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + mTestLooper.dispatchAll(); + verify(newTransform).getIpSecTransformState(any(), any()); + } + + @Test + public void testStartedMonitor_updateCarrierConfig() throws Exception { + startMonitorAndCaptureStateReceiver(); + + final int additionalPollIntervalMs = (int) TimeUnit.SECONDS.toMillis(10L); + when(mCarrierConfig.getInt( + eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt())) + .thenReturn( + (int) + TimeUnit.MILLISECONDS.toSeconds( + POLL_IPSEC_STATE_INTERVAL_MS + additionalPollIntervalMs)); + mIpSecPacketLossDetector.setCarrierConfig(mCarrierConfig); + mTestLooper.dispatchAll(); + + // The already scheduled event is still fired with the old timeout + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + mTestLooper.dispatchAll(); + + // The next scheduled event will take 10 more seconds to fire + mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS); + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(additionalPollIntervalMs); + assertNotNull(mTestLooper.nextMessage()); + } + + @Test + public void testStopMonitor() throws Exception { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertNotNull(mTestLooper.nextMessage()); + + // Unselect the monitor + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */); + verifyStopped(); + } + + @Test + public void testClose() throws Exception { + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */); + mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform); + + assertTrue(mIpSecPacketLossDetector.isStarted()); + assertNotNull(mTestLooper.nextMessage()); + + // Stop the monitor + mIpSecPacketLossDetector.close(); + verifyStopped(); + verify(mIpSecTransform).close(); + } + + @Test + public void testTransformStateReceiverOnResultWhenStopped() throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + xfrmStateReceiver.onResult(mTransformStateInitial); + + // Unselect the monitor + mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */); + verifyStopped(); + + xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1))); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + } + + @Test + public void testTransformStateReceiverOnError() throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + xfrmStateReceiver.onResult(mTransformStateInitial); + + xfrmStateReceiver.onError(new RuntimeException("Test")); + verify(mPacketLossCalculator, never()) + .getPacketLossRatePercentage(any(), any(), anyString()); + } + + private void checkHandleLossRate( + int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected) + throws Exception { + final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver = + startMonitorAndCaptureStateReceiver(); + doReturn(mockPacketLossRate) + .when(mPacketLossCalculator) + .getPacketLossRatePercentage(any(), any(), anyString()); + + // Mock receiving two states with mTransformStateInitial and an arbitrary transformNew + final IpSecTransformState transformNew = newTransformState(1, 1, newReplayBitmap(1)); + xfrmStateReceiver.onResult(mTransformStateInitial); + xfrmStateReceiver.onResult(transformNew); + + // Verifications + verify(mPacketLossCalculator) + .getPacketLossRatePercentage( + eq(mTransformStateInitial), eq(transformNew), anyString()); + + if (isLastStateExpectedToUpdate) { + assertEquals(transformNew, mIpSecPacketLossDetector.getLastTransformState()); + } else { + assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState()); + } + + if (isCallbackExpected) { + verify(mMetricMonitorCallback).onValidationResultReceived(); + } else { + verify(mMetricMonitorCallback, never()).onValidationResultReceived(); + } + } + + @Test + public void testHandleLossRate_validationPass() throws Exception { + checkHandleLossRate( + 2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_validationFail() throws Exception { + checkHandleLossRate( + 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */); + } + + @Test + public void testHandleLossRate_resultUnavalaible() throws Exception { + checkHandleLossRate( + PACKET_LOSS_UNAVALAIBLE, + false /* isLastStateExpectedToUpdate */, + false /* isCallbackExpected */); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate) + throws Exception { + assertEquals( + expectedLossRate, + mPacketLossCalculator.getPacketLossRatePercentage(oldState, newState, TAG)); + } + + private void checkGetPacketLossRate( + IpSecTransformState oldState, + int rxSeqNo, + int packetCount, + int packetInWin, + int expectedDataLossRate) + throws Exception { + final IpSecTransformState newState = + newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin)); + checkGetPacketLossRate(oldState, newState, expectedDataLossRate); + } + + @Test + public void testGetPacketLossRate_replayWindowUnchanged() throws Exception { + checkGetPacketLossRate( + mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE); + checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE); + } + + @Test + public void testGetPacketLossRate_againstInitialState() throws Exception { + checkGetPacketLossRate(mTransformStateInitial, 7000, 7001, 4096, 0); + checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4096, 15); + checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4000, 14); + } + + @Test + public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_overlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500)); + + checkGetPacketLossRate(oldState, 5000, 5001, 4096, 0); + checkGetPacketLossRate(oldState, 5000, 4000, 4096, 29); + checkGetPacketLossRate(oldState, 5000, 4000, 4000, 27); + } + + @Test + public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_notOverlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500)); + + checkGetPacketLossRate(oldState, 7000, 7001, 4096, 0); + checkGetPacketLossRate(oldState, 7000, 5000, 4096, 37); + checkGetPacketLossRate(oldState, 7000, 5000, 3000, 21); + } + + @Test + public void testGetPktLossRate_oldHiSeqLargerThanWinSize_overlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000)); + + checkGetPacketLossRate(oldState, 12000, 8096, 4096, 0); + checkGetPacketLossRate(oldState, 12000, 7000, 4096, 36); + checkGetPacketLossRate(oldState, 12000, 7000, 3000, 0); + } + + @Test + public void testGetPktLossRate_oldHiSeqLargerThanWinSize_notOverlappedWithNewWin() + throws Exception { + final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000)); + + checkGetPacketLossRate(oldState, 20000, 16096, 4096, 0); + checkGetPacketLossRate(oldState, 20000, 14000, 4096, 19); + checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10); + } +} diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java new file mode 100644 index 000000000000..6015e9318464 --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static com.android.server.vcn.VcnTestUtils.setupSystemService; +import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; + +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.IpSecConfig; +import android.net.IpSecTransform; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.TelephonyNetworkSpecifier; +import android.net.vcn.FeatureFlags; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IThermalService; +import android.os.ParcelUuid; +import android.os.PowerManager; +import android.os.test.TestLooper; +import android.telephony.TelephonyManager; + +import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; +import com.android.server.vcn.VcnContext; +import com.android.server.vcn.VcnNetworkProvider; + +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Set; +import java.util.UUID; + +public abstract class NetworkEvaluationTestBase { + protected static final String SSID = "TestWifi"; + protected static final String SSID_OTHER = "TestWifiOther"; + protected static final String PLMN_ID = "123456"; + protected static final String PLMN_ID_OTHER = "234567"; + + protected static final int SUB_ID = 1; + protected static final int WIFI_RSSI = -60; + protected static final int WIFI_RSSI_HIGH = -50; + protected static final int WIFI_RSSI_LOW = -80; + protected static final int CARRIER_ID = 1; + protected static final int CARRIER_ID_OTHER = 2; + + protected static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024; + protected static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048; + + protected static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100; + protected static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200; + + protected static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); + + protected static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .setSignalStrength(WIFI_RSSI) + .setSsid(SSID) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) + .build(); + + protected static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = + new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); + protected static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = + new NetworkCapabilities.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .setSubscriptionIds(Set.of(SUB_ID)) + .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) + .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) + .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) + .build(); + + protected static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); + + @Mock protected Context mContext; + @Mock protected Network mNetwork; + @Mock protected FeatureFlags mFeatureFlags; + @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags; + @Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot; + @Mock protected TelephonyManager mTelephonyManager; + @Mock protected IPowerManager mPowerManagerService; + + protected TestLooper mTestLooper; + protected VcnContext mVcnContext; + protected PowerManager mPowerManager; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mNetwork.getNetId()).thenReturn(-1); + + mTestLooper = new TestLooper(); + mVcnContext = + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mock(VcnNetworkProvider.class), + false /* isInTestMode */)); + doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + + doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled(); + doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); + + setupSystemService( + mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); + when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); + when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); + when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); + + mPowerManager = + new PowerManager( + mContext, + mPowerManagerService, + mock(IThermalService.class), + mock(Handler.class)); + setupSystemService(mContext, mPowerManager, Context.POWER_SERVICE, PowerManager.class); + } + + protected IpSecTransform makeDummyIpSecTransform() throws Exception { + return new IpSecTransform(mContext, new IpSecConfig()); + } +} diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java index 226604108522..d85c5150f53f 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java @@ -24,152 +24,48 @@ import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTR import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS; import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS; -import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_FALLBACK; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesCellPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesPriorityRule; import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.checkMatchesWifiPriorityRule; -import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; -import android.content.Context; -import android.net.LinkProperties; -import android.net.Network; import android.net.NetworkCapabilities; -import android.net.TelephonyNetworkSpecifier; import android.net.vcn.VcnCellUnderlyingNetworkTemplate; import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkTemplate; import android.net.vcn.VcnWifiUnderlyingNetworkTemplate; -import android.os.ParcelUuid; import android.os.PersistableBundle; -import android.os.test.TestLooper; -import android.telephony.TelephonyManager; import android.util.ArraySet; -import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import com.android.server.vcn.VcnContext; -import com.android.server.vcn.VcnNetworkProvider; - import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.UUID; - -public class NetworkPriorityClassifierTest { - private static final String SSID = "TestWifi"; - private static final String SSID_OTHER = "TestWifiOther"; - private static final String PLMN_ID = "123456"; - private static final String PLMN_ID_OTHER = "234567"; - - private static final int SUB_ID = 1; - private static final int WIFI_RSSI = -60; - private static final int WIFI_RSSI_HIGH = -50; - private static final int WIFI_RSSI_LOW = -80; - private static final int CARRIER_ID = 1; - private static final int CARRIER_ID_OTHER = 2; - - private static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024; - private static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048; - - private static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100; - private static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200; - - private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0)); - - private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES = - new NetworkCapabilities.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .setSignalStrength(WIFI_RSSI) - .setSsid(SSID) - .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) - .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) - .build(); - - private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER = - new TelephonyNetworkSpecifier.Builder().setSubscriptionId(SUB_ID).build(); - private static final NetworkCapabilities CELL_NETWORK_CAPABILITIES = - new NetworkCapabilities.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .addCapability(NetworkCapabilities.NET_CAPABILITY_DUN) - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setSubscriptionIds(Set.of(SUB_ID)) - .setNetworkSpecifier(TEL_NETWORK_SPECIFIER) - .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS) - .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS) - .build(); - - private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface"); - - @Mock private Network mNetwork; - @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; - @Mock private TelephonyManager mTelephonyManager; - - private TestLooper mTestLooper; - private VcnContext mVcnContext; + +public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase { private UnderlyingNetworkRecord mWifiNetworkRecord; private UnderlyingNetworkRecord mCellNetworkRecord; @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - final Context mockContext = mock(Context.class); - mTestLooper = new TestLooper(); - mVcnContext = - spy( - new VcnContext( - mockContext, - mTestLooper.getLooper(), - mock(VcnNetworkProvider.class), - false /* isInTestMode */)); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - - setupSystemService( - mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class); - when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager); - when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID); - when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID); - - mWifiNetworkRecord = - getTestNetworkRecord( - WIFI_NETWORK_CAPABILITIES, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); - mCellNetworkRecord = - getTestNetworkRecord( - CELL_NETWORK_CAPABILITIES, - VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES); - } - - private UnderlyingNetworkRecord getTestNetworkRecord( - NetworkCapabilities nc, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) { - return new UnderlyingNetworkRecord( - mNetwork, - nc, - LINK_PROPERTIES, - false /* isBlocked */, - mVcnContext, - underlyingNetworkTemplates, - SUB_GROUP, - mSubscriptionSnapshot, - null /* currentlySelected */, - null /* carrierConfig */); + public void setUp() throws Exception { + super.setUp(); + + mWifiNetworkRecord = getTestNetworkRecord(WIFI_NETWORK_CAPABILITIES); + mCellNetworkRecord = getTestNetworkRecord(CELL_NETWORK_CAPABILITIES); + } + + private UnderlyingNetworkRecord getTestNetworkRecord(NetworkCapabilities nc) { + return new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */); } @Test @@ -186,14 +82,14 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - null /* currentlySelecetd */, + false /* isSelected */, null /* carrierConfig */)); } private void verifyMatchesPriorityRuleForUpstreamBandwidth( int entryUpstreamBandwidth, int exitUpstreamBandwidth, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, boolean expectMatch) { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() @@ -208,14 +104,14 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - currentlySelected, + isSelected, null /* carrierConfig */)); } private void verifyMatchesPriorityRuleForDownstreamBandwidth( int entryDownstreamBandwidth, int exitDownstreamBandwidth, - UnderlyingNetworkRecord currentlySelected, + boolean isSelected, boolean expectMatch) { final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority = new VcnWifiUnderlyingNetworkTemplate.Builder() @@ -231,7 +127,7 @@ public class NetworkPriorityClassifierTest { mWifiNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - currentlySelected, + isSelected, null /* carrierConfig */)); } @@ -240,7 +136,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, - null /* currentlySelected */, + false /* isSelected */, true); } @@ -249,7 +145,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( LINK_UPSTREAM_BANDWIDTH_KBPS + 1, LINK_UPSTREAM_BANDWIDTH_KBPS + 1, - null /* currentlySelected */, + false /* isSelected */, false); } @@ -258,7 +154,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, - null /* currentlySelected */, + false /* isSelected */, true); } @@ -267,7 +163,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, - null /* currentlySelected */, + false /* isSelected */, false); } @@ -276,7 +172,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS, - mWifiNetworkRecord, + true /* isSelected */, true); } @@ -285,7 +181,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForUpstreamBandwidth( LINK_UPSTREAM_BANDWIDTH_KBPS + 1, LINK_UPSTREAM_BANDWIDTH_KBPS + 1, - mWifiNetworkRecord, + true /* isSelected */, false); } @@ -294,7 +190,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS, - mWifiNetworkRecord, + true /* isSelected */, true); } @@ -303,7 +199,7 @@ public class NetworkPriorityClassifierTest { verifyMatchesPriorityRuleForDownstreamBandwidth( LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1, - mWifiNetworkRecord, + true /* isSelected */, false); } @@ -318,14 +214,12 @@ public class NetworkPriorityClassifierTest { TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS, TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS) .build(); - final UnderlyingNetworkRecord selectedNetworkRecord = - isSelectedNetwork ? mWifiNetworkRecord : null; assertEquals( expectMatch, checkMatchesWifiPriorityRule( wifiNetworkPriority, mWifiNetworkRecord, - selectedNetworkRecord, + isSelectedNetwork, carrierConfig == null ? null : new PersistableBundleWrapper(carrierConfig))); @@ -381,7 +275,7 @@ public class NetworkPriorityClassifierTest { checkMatchesWifiPriorityRule( wifiNetworkPriority, mWifiNetworkRecord, - null /* currentlySelecetd */, + false /* isSelected */, null /* carrierConfig */)); } @@ -516,7 +410,7 @@ public class NetworkPriorityClassifierTest { mCellNetworkRecord, SUB_GROUP, mSubscriptionSnapshot, - null /* currentlySelected */, + false /* isSelected */, null /* carrierConfig */)); } @@ -543,7 +437,16 @@ public class NetworkPriorityClassifierTest { @Test public void testCalculatePriorityClass() throws Exception { - assertEquals(2, mCellNetworkRecord.priorityClass); + final int priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + mCellNetworkRecord, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + false /* isSelected */, + null /* carrierConfig */); + assertEquals(2, priorityClass); } private void checkCalculatePriorityClassFailToMatchAny( @@ -561,10 +464,19 @@ public class NetworkPriorityClassifierTest { ncBuilder.addCapability(NET_CAPABILITY_INTERNET); } - final UnderlyingNetworkRecord nonDunNetworkRecord = - getTestNetworkRecord(ncBuilder.build(), templatesRequireDun); + final UnderlyingNetworkRecord nonDunNetworkRecord = getTestNetworkRecord(ncBuilder.build()); + + final int priorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + mVcnContext, + nonDunNetworkRecord, + templatesRequireDun, + SUB_GROUP, + mSubscriptionSnapshot, + false /* isSelected */, + null /* carrierConfig */); - assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass); + assertEquals(expectedPriorityClass, priorityClass); } @Test diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 2941fdea20bb..588624b56221 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -29,13 +29,12 @@ import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WI import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.WIFI_EXIT_RSSI_THRESHOLD_DEFAULT; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -48,6 +47,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.ConnectivityManager; +import android.net.IpSecConfig; +import android.net.IpSecTransform; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -67,9 +68,11 @@ import android.util.ArraySet; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; import com.android.server.vcn.VcnNetworkProvider; +import com.android.server.vcn.routeselection.UnderlyingNetworkController.Dependencies; import com.android.server.vcn.routeselection.UnderlyingNetworkController.NetworkBringupCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkControllerCallback; import com.android.server.vcn.routeselection.UnderlyingNetworkController.UnderlyingNetworkListener; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; import org.junit.Before; import org.junit.Test; @@ -77,6 +80,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.Spy; import java.util.ArrayList; import java.util.Arrays; @@ -152,12 +156,17 @@ public class UnderlyingNetworkControllerTest { @Mock private CarrierConfigManager mCarrierConfigManager; @Mock private TelephonySubscriptionSnapshot mSubscriptionSnapshot; @Mock private UnderlyingNetworkControllerCallback mNetworkControllerCb; + @Mock private NetworkEvaluatorCallback mEvaluatorCallback; @Mock private Network mNetwork; + @Spy private Dependencies mDependencies = new Dependencies(); + @Captor private ArgumentCaptor<UnderlyingNetworkListener> mUnderlyingNetworkListenerCaptor; + @Captor private ArgumentCaptor<NetworkEvaluatorCallback> mEvaluatorCallbackCaptor; private TestLooper mTestLooper; private VcnContext mVcnContext; + private UnderlyingNetworkEvaluator mNetworkEvaluator; private UnderlyingNetworkController mUnderlyingNetworkController; @Before @@ -172,7 +181,7 @@ public class UnderlyingNetworkControllerTest { mTestLooper.getLooper(), mVcnNetworkProvider, false /* isInTestMode */)); - resetVcnContext(); + resetVcnContext(mVcnContext); setupSystemService( mContext, @@ -189,18 +198,36 @@ public class UnderlyingNetworkControllerTest { when(mSubscriptionSnapshot.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(INITIAL_SUB_IDS); + mNetworkEvaluator = + spy( + new UnderlyingNetworkEvaluator( + mVcnContext, + mNetwork, + VcnGatewayConnectionConfigTest.buildTestConfig() + .getVcnUnderlyingNetworkPriorities(), + SUB_GROUP, + mSubscriptionSnapshot, + null, + mEvaluatorCallback)); + doReturn(mNetworkEvaluator) + .when(mDependencies) + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any(), any()); + mUnderlyingNetworkController = new UnderlyingNetworkController( mVcnContext, VcnGatewayConnectionConfigTest.buildTestConfig(), SUB_GROUP, mSubscriptionSnapshot, - mNetworkControllerCb); + mNetworkControllerCb, + mDependencies); } - private void resetVcnContext() { - reset(mVcnContext); - doNothing().when(mVcnContext).ensureRunningOnLooperThread(); + private void resetVcnContext(VcnContext vcnContext) { + reset(vcnContext); + doNothing().when(vcnContext).ensureRunningOnLooperThread(); + doReturn(true).when(vcnContext).isFlagNetworkMetricMonitorEnabled(); + doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled(); } // Package private for use in NetworkPriorityClassifierTest @@ -226,11 +253,13 @@ public class UnderlyingNetworkControllerTest { final ConnectivityManager cm = mock(ConnectivityManager.class); setupSystemService(mContext, cm, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); final VcnContext vcnContext = - new VcnContext( - mContext, - mTestLooper.getLooper(), - mVcnNetworkProvider, - true /* isInTestMode */); + spy( + new VcnContext( + mContext, + mTestLooper.getLooper(), + mVcnNetworkProvider, + true /* isInTestMode */)); + resetVcnContext(vcnContext); new UnderlyingNetworkController( vcnContext, @@ -489,13 +518,7 @@ public class UnderlyingNetworkControllerTest { NetworkCapabilities networkCapabilities, LinkProperties linkProperties, boolean isBlocked) { - return new UnderlyingNetworkRecord( - network, - networkCapabilities, - linkProperties, - isBlocked, - false /* isSelected */, - 0 /* priorityClass */); + return new UnderlyingNetworkRecord(network, networkCapabilities, linkProperties, isBlocked); } @Test @@ -515,24 +538,12 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkRecord recordC = new UnderlyingNetworkRecord( mNetwork, - INITIAL_NETWORK_CAPABILITIES, - INITIAL_LINK_PROPERTIES, - false /* isBlocked */, - true /* isSelected */, - -1 /* priorityClass */); - UnderlyingNetworkRecord recordD = - getTestNetworkRecord( - mNetwork, UPDATED_NETWORK_CAPABILITIES, UPDATED_LINK_PROPERTIES, false /* isBlocked */); assertEquals(recordA, recordB); - assertEquals(recordA, recordC); - assertNotEquals(recordA, recordD); - - assertTrue(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordB)); - assertFalse(UnderlyingNetworkRecord.isEqualIncludingPriorities(recordA, recordC)); + assertNotEquals(recordA, recordC); } @Test @@ -540,6 +551,58 @@ public class UnderlyingNetworkControllerTest { verifyRegistrationOnAvailableAndGetCallback(); } + @Test + public void testUpdateSubscriptionSnapshotAndCarrierConfig() { + verifyRegistrationOnAvailableAndGetCallback(); + + TelephonySubscriptionSnapshot subscriptionUpdate = + mock(TelephonySubscriptionSnapshot.class); + when(subscriptionUpdate.getAllSubIdsInGroup(eq(SUB_GROUP))).thenReturn(UPDATED_SUB_IDS); + + mUnderlyingNetworkController.updateSubscriptionSnapshot(subscriptionUpdate); + + verify(mNetworkEvaluator).reevaluate(any(), any(), any(), any()); + } + + @Test + public void testUpdateIpSecTransform() { + verifyRegistrationOnAvailableAndGetCallback(); + + final UnderlyingNetworkRecord expectedRecord = + getTestNetworkRecord( + mNetwork, + INITIAL_NETWORK_CAPABILITIES, + INITIAL_LINK_PROPERTIES, + false /* isBlocked */); + final IpSecTransform expectedTransform = new IpSecTransform(mContext, new IpSecConfig()); + + mUnderlyingNetworkController.updateInboundTransform(expectedRecord, expectedTransform); + verify(mNetworkEvaluator).setInboundTransform(expectedTransform); + } + + @Test + public void testOnEvaluationResultChanged() { + verifyRegistrationOnAvailableAndGetCallback(); + + // Verify #reevaluateNetworks is called by checking #getNetworkRecord + verify(mNetworkEvaluator).getNetworkRecord(); + + // Trigger the callback + verify(mDependencies) + .newUnderlyingNetworkEvaluator( + any(), + any(), + any(), + any(), + any(), + any(), + mEvaluatorCallbackCaptor.capture()); + mEvaluatorCallbackCaptor.getValue().onEvaluationResultChanged(); + + // Verify #reevaluateNetworks is called again + verify(mNetworkEvaluator, times(2)).getNetworkRecord(); + } + private UnderlyingNetworkListener verifyRegistrationOnAvailableAndGetCallback() { return verifyRegistrationOnAvailableAndGetCallback(INITIAL_NETWORK_CAPABILITIES); } @@ -583,6 +646,7 @@ public class UnderlyingNetworkControllerTest { INITIAL_LINK_PROPERTIES, false /* isBlocked */); verifyOnSelectedUnderlyingNetworkChanged(expectedRecord); + verify(mNetworkEvaluator).setIsSelected(eq(true), any(), any(), any(), any()); return cb; } @@ -667,7 +731,7 @@ public class UnderlyingNetworkControllerTest { cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */); - verifyOnSelectedUnderlyingNetworkChanged(null); + verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); } @Test @@ -675,6 +739,7 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback(); cb.onLost(mNetwork); + verify(mNetworkEvaluator).close(); verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null); } @@ -713,7 +778,8 @@ public class UnderlyingNetworkControllerTest { VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates), SUB_GROUP, mSubscriptionSnapshot, - mNetworkControllerCb); + mNetworkControllerCb, + mDependencies); verify(cm) .registerNetworkCallback( @@ -724,30 +790,44 @@ public class UnderlyingNetworkControllerTest { return mUnderlyingNetworkListenerCaptor.getValue(); } - private UnderlyingNetworkRecord bringupNetworkAndGetRecord( + private UnderlyingNetworkEvaluator bringupNetworkAndGetEvaluator( UnderlyingNetworkListener cb, NetworkCapabilities requestNetworkCaps, - List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, - UnderlyingNetworkRecord currentlySelected) { + List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates) { final Network network = mock(Network.class); final NetworkCapabilities responseNetworkCaps = buildResponseNwCaps(requestNetworkCaps, INITIAL_SUB_IDS); + final UnderlyingNetworkEvaluator evaluator = + spy( + new UnderlyingNetworkEvaluator( + mVcnContext, + network, + underlyingNetworkTemplates, + SUB_GROUP, + mSubscriptionSnapshot, + null, + mEvaluatorCallback)); + doReturn(evaluator) + .when(mDependencies) + .newUnderlyingNetworkEvaluator(any(), any(), any(), any(), any(), any(), any()); cb.onAvailable(network); cb.onCapabilitiesChanged(network, responseNetworkCaps); cb.onLinkPropertiesChanged(network, INITIAL_LINK_PROPERTIES); cb.onBlockedStatusChanged(network, false /* isFalse */); - return new UnderlyingNetworkRecord( - network, - responseNetworkCaps, - INITIAL_LINK_PROPERTIES, - false /* isBlocked */, - mVcnContext, - underlyingNetworkTemplates, - SUB_GROUP, - mSubscriptionSnapshot, - currentlySelected, - null /* carrierConfig */); + + return evaluator; + } + + private void verifySelectNetwork(UnderlyingNetworkEvaluator expectedEvaluator) { + verifyOnSelectedUnderlyingNetworkChanged(expectedEvaluator.getNetworkRecord()); + verify(expectedEvaluator).setIsSelected(eq(true), any(), any(), any(), any()); + } + + private void verifyNeverSelectNetwork(UnderlyingNetworkEvaluator expectedEvaluator) { + verify(mNetworkControllerCb, never()) + .onSelectedUnderlyingNetworkChanged(eq(expectedEvaluator.getNetworkRecord())); + verify(expectedEvaluator, never()).setIsSelected(eq(true), any(), any(), any(), any()); } @Test @@ -759,19 +839,15 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up CBS network - final UnderlyingNetworkRecord cbsNetworkRecord = - bringupNetworkAndGetRecord( - cb, - CBS_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + final UnderlyingNetworkEvaluator cbsNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(cbsNetworkEvaluator); // Bring up DUN network - final UnderlyingNetworkRecord dunNetworkRecord = - bringupNetworkAndGetRecord( - cb, DUN_NETWORK_CAPABILITIES, networkTemplates, cbsNetworkRecord); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + final UnderlyingNetworkEvaluator dunNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, DUN_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(dunNetworkEvaluator); + verify(cbsNetworkEvaluator).setIsSelected(eq(false), any(), any(), any(), any()); } @Test @@ -783,20 +859,14 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up DUN network - final UnderlyingNetworkRecord dunNetworkRecord = - bringupNetworkAndGetRecord( - cb, - DUN_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(dunNetworkRecord)); + final UnderlyingNetworkEvaluator dunNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, DUN_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(dunNetworkEvaluator); // Bring up CBS network - final UnderlyingNetworkRecord cbsNetworkRecord = - bringupNetworkAndGetRecord( - cb, CBS_NETWORK_CAPABILITIES, networkTemplates, dunNetworkRecord); - verify(mNetworkControllerCb, never()) - .onSelectedUnderlyingNetworkChanged(eq(cbsNetworkRecord)); + final UnderlyingNetworkEvaluator cbsNetworkEvaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifyNeverSelectNetwork(cbsNetworkEvaluator); } @Test @@ -808,13 +878,9 @@ public class UnderlyingNetworkControllerTest { UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); // Bring up an Internet network without DUN capability - final UnderlyingNetworkRecord networkRecord = - bringupNetworkAndGetRecord( - cb, - INITIAL_NETWORK_CAPABILITIES, - networkTemplates, - null /* currentlySelected */); - verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(eq(networkRecord)); + final UnderlyingNetworkEvaluator evaluator = + bringupNetworkAndGetEvaluator(cb, INITIAL_NETWORK_CAPABILITIES, networkTemplates); + verifySelectNetwork(evaluator); } @Test @@ -825,10 +891,8 @@ public class UnderlyingNetworkControllerTest { new VcnCellUnderlyingNetworkTemplate.Builder().setDun(MATCH_REQUIRED).build()); UnderlyingNetworkListener cb = setupControllerAndGetNetworkListener(networkTemplates); - bringupNetworkAndGetRecord( - cb, CBS_NETWORK_CAPABILITIES, networkTemplates, null /* currentlySelected */); - - verify(mNetworkControllerCb, never()) - .onSelectedUnderlyingNetworkChanged(any(UnderlyingNetworkRecord.class)); + final UnderlyingNetworkEvaluator evaluator = + bringupNetworkAndGetEvaluator(cb, CBS_NETWORK_CAPABILITIES, networkTemplates); + verifyNeverSelectNetwork(evaluator); } } diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java new file mode 100644 index 000000000000..aa81efe9a1ce --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2023 The Android Open 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.vcn.routeselection; + +import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY; + +import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_INVALID; +import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyObject; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.net.IpSecTransform; +import android.net.vcn.VcnGatewayConnectionConfig; + +import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.Dependencies; +import com.android.server.vcn.routeselection.UnderlyingNetworkEvaluator.NetworkEvaluatorCallback; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; + +import java.util.concurrent.TimeUnit; + +public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase { + private static final int PENALTY_TIMEOUT_MIN = 10; + private static final long PENALTY_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(PENALTY_TIMEOUT_MIN); + + @Mock private PersistableBundleWrapper mCarrierConfig; + @Mock private IpSecPacketLossDetector mIpSecPacketLossDetector; + @Mock private Dependencies mDependencies; + @Mock private NetworkEvaluatorCallback mEvaluatorCallback; + + @Captor private ArgumentCaptor<NetworkMetricMonitorCallback> mMetricMonitorCbCaptor; + + private UnderlyingNetworkEvaluator mNetworkEvaluator; + + @Before + public void setUp() throws Exception { + super.setUp(); + + when(mDependencies.newIpSecPacketLossDetector(any(), any(), any(), any())) + .thenReturn(mIpSecPacketLossDetector); + + when(mCarrierConfig.getIntArray( + eq(VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY), anyObject())) + .thenReturn(new int[] {PENALTY_TIMEOUT_MIN}); + + mNetworkEvaluator = newValidUnderlyingNetworkEvaluator(); + } + + private UnderlyingNetworkEvaluator newUnderlyingNetworkEvaluator() { + return new UnderlyingNetworkEvaluator( + mVcnContext, + mNetwork, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig, + mEvaluatorCallback, + mDependencies); + } + + private UnderlyingNetworkEvaluator newValidUnderlyingNetworkEvaluator() { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + + evaluator.setNetworkCapabilities( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setLinkProperties( + LINK_PROPERTIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setIsBlocked( + false /* isBlocked */, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + return evaluator; + } + + @Test + public void testInitializedEvaluator() throws Exception { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + + assertFalse(evaluator.isValid()); + assertEquals(mNetwork, evaluator.getNetwork()); + assertEquals(PRIORITY_INVALID, evaluator.getPriorityClass()); + + try { + evaluator.getNetworkRecord(); + fail("Expected to fail because evaluator is not valid"); + } catch (Exception expected) { + } + } + + @Test + public void testValidEvaluator() { + final UnderlyingNetworkEvaluator evaluator = newUnderlyingNetworkEvaluator(); + evaluator.setNetworkCapabilities( + CELL_NETWORK_CAPABILITIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setLinkProperties( + LINK_PROPERTIES, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + evaluator.setIsBlocked( + false /* isBlocked */, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + + final UnderlyingNetworkRecord expectedRecord = + new UnderlyingNetworkRecord( + mNetwork, + CELL_NETWORK_CAPABILITIES, + LINK_PROPERTIES, + false /* isBlocked */); + + assertTrue(evaluator.isValid()); + assertEquals(mNetwork, evaluator.getNetwork()); + assertEquals(2, evaluator.getPriorityClass()); + assertEquals(expectedRecord, evaluator.getNetworkRecord()); + } + + private void checkSetSelectedNetwork(boolean isSelected) { + mNetworkEvaluator.setIsSelected( + isSelected, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + verify(mIpSecPacketLossDetector).setIsSelectedUnderlyingNetwork(isSelected); + } + + @Test + public void testSetIsSelected_selected() throws Exception { + checkSetSelectedNetwork(true /* isSelectedExpected */); + } + + @Test + public void testSetIsSelected_unselected() throws Exception { + checkSetSelectedNetwork(false /* isSelectedExpected */); + } + + @Test + public void testSetIpSecTransform_onSelectedNetwork() throws Exception { + final IpSecTransform transform = makeDummyIpSecTransform(); + + // Make the network selected + mNetworkEvaluator.setIsSelected( + true, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + mNetworkEvaluator.setInboundTransform(transform); + + verify(mIpSecPacketLossDetector).setInboundTransform(transform); + } + + @Test + public void testSetIpSecTransform_onUnSelectedNetwork() throws Exception { + mNetworkEvaluator.setIsSelected( + false, + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + mNetworkEvaluator.setInboundTransform(makeDummyIpSecTransform()); + + verify(mIpSecPacketLossDetector, never()).setInboundTransform(any()); + } + + @Test + public void close() throws Exception { + mNetworkEvaluator.close(); + + verify(mIpSecPacketLossDetector).close(); + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + private NetworkMetricMonitorCallback getMetricMonitorCbCaptor() throws Exception { + verify(mDependencies) + .newIpSecPacketLossDetector(any(), any(), any(), mMetricMonitorCbCaptor.capture()); + + return mMetricMonitorCbCaptor.getValue(); + } + + private void checkPenalizeNetwork() throws Exception { + assertFalse(mNetworkEvaluator.isPenalized()); + + // Validation failed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(true); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verify the evaluator is penalized + assertTrue(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback).onEvaluationResultChanged(); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_penaltyTimeout() throws Exception { + checkPenalizeNetwork(); + + // Penalty timeout + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + mTestLooper.dispatchAll(); + + // Verify the evaluator is not penalized + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, times(2)).onEvaluationResultChanged(); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_passValidation() throws Exception { + checkPenalizeNetwork(); + + // Validation passed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(false); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verify the evaluator is not penalized and penalty timeout is canceled + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, times(2)).onEvaluationResultChanged(); + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testRcvValidationResult_penalizeNetwork_closeEvaluator() throws Exception { + checkPenalizeNetwork(); + + mNetworkEvaluator.close(); + + // Verify penalty timeout is canceled + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + } + + @Test + public void testRcvValidationResult_PenaltyStateUnchanged() throws Exception { + assertFalse(mNetworkEvaluator.isPenalized()); + + // Validation passed + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(false); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + // Verifications + assertFalse(mNetworkEvaluator.isPenalized()); + verify(mEvaluatorCallback, never()).onEvaluationResultChanged(); + } + + @Test + public void testSetCarrierConfig() throws Exception { + final int additionalTimeoutMin = 10; + when(mCarrierConfig.getIntArray( + eq(VCN_NETWORK_SELECTION_PENALTY_TIMEOUT_MINUTES_LIST_KEY), anyObject())) + .thenReturn(new int[] {PENALTY_TIMEOUT_MIN + additionalTimeoutMin}); + + // Update evaluator and penalize the network + mNetworkEvaluator.reevaluate( + VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES, + SUB_GROUP, + mSubscriptionSnapshot, + mCarrierConfig); + checkPenalizeNetwork(); + + // Verify penalty timeout is changed + mTestLooper.moveTimeForward(PENALTY_TIMEOUT_MS); + assertNull(mTestLooper.nextMessage()); + mTestLooper.moveTimeForward(TimeUnit.MINUTES.toMillis(additionalTimeoutMin)); + assertNotNull(mTestLooper.nextMessage()); + + // Verify NetworkMetricMonitor is notified + verify(mIpSecPacketLossDetector).setCarrierConfig(any()); + } + + @Test + public void testCompare() throws Exception { + when(mIpSecPacketLossDetector.isValidationFailed()).thenReturn(true); + getMetricMonitorCbCaptor().onValidationResultReceived(); + + final UnderlyingNetworkEvaluator penalized = mNetworkEvaluator; + final UnderlyingNetworkEvaluator notPenalized = newValidUnderlyingNetworkEvaluator(); + + assertEquals(penalized.getPriorityClass(), notPenalized.getPriorityClass()); + + final int result = + UnderlyingNetworkEvaluator.getComparator(mVcnContext) + .compare(penalized, notPenalized); + assertEquals(1, result); + } +} |