Merge "Fixing issues in Maximize Menu" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 9e30843..ce311d0 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -71,6 +71,9 @@
":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 @@
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 @@
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 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
+ "com.android.nfcservices",
],
-
}
// SQLite
@@ -743,6 +746,11 @@
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 @@
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 82b844b..a3e39018 100644
--- a/Android.bp
+++ b/Android.bp
@@ -175,9 +175,6 @@
// 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 @@
],
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 @@
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 @@
],
compile_dex: false,
headers_only: true,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -534,7 +521,7 @@
},
lint: {
enabled: false,
- baseline_filename: "lint-baseline.xml",
+
},
}
@@ -559,9 +546,6 @@
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -577,9 +561,6 @@
"calendar-provider-compat-config",
"contacts-provider-platform-compat-config",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
platform_compat_config {
@@ -634,9 +615,6 @@
"rappor",
],
dxflags: ["--core-library"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// utility classes statically linked into framework-wifi and dynamically linked
@@ -665,6 +643,7 @@
lint: {
baseline_filename: "lint-baseline.xml",
},
+ apex_available: ["com.android.wifi"],
}
filegroup {
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d59775f..ecfd86c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -138,15 +138,14 @@
}
],
"postsubmit-ravenwood": [
- // TODO(ravenwood) promote it to presubmit
- // TODO: Enable it once the infra knows how to run it.
-// {
-// "name": "CtsUtilTestCasesRavenwood",
-// "file_patterns": [
-// "*Ravenwood*",
-// "*ravenwood*"
-// ]
-// }
+ {
+ "name": "CtsUtilTestCasesRavenwood",
+ "host": true,
+ "file_patterns": [
+ "*Ravenwood*",
+ "*ravenwood*"
+ ]
+ }
],
"postsubmit-managedprofile-stress": [
{
diff --git a/WEAR_OWNERS b/WEAR_OWNERS
index 4f3bc27..4127f99 100644
--- a/WEAR_OWNERS
+++ b/WEAR_OWNERS
@@ -4,3 +4,9 @@
adsule@google.com
andriyn@google.com
yfz@google.com
+con@google.com
+leetodd@google.com
+sadrul@google.com
+rwmyers@google.com
+nalmalki@google.com
+shijianli@google.com
diff --git a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
index b7460cd..fa4387b 100644
--- a/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
+++ b/apct-tests/perftests/core/src/android/database/SQLiteDatabasePerfTest.java
@@ -433,6 +433,17 @@
performMultithreadedReadWriteTest();
}
+ /**
+ * This test measures a multi-threaded read-write environment where there are 2 readers and
+ * 1 writer in the database using WAL journal mode and NORMAL syncMode.
+ */
+ @Test
+ public void testMultithreadedReadWriteWithWalNormal() {
+ recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
+ insertT1TestDataSet();
+ performMultithreadedReadWriteTest();
+ }
+
private void doReadLoop(int totalIterations) {
Random rnd = new Random(0);
int currentIteration = 0;
@@ -472,7 +483,6 @@
}
private void doUpdateLoop(int totalIterations) {
- SQLiteDatabase db = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
Random rnd = new Random(0);
int i = 0;
ContentValues cv = new ContentValues();
@@ -485,24 +495,12 @@
cv.put("COL_B", "UpdatedValue");
cv.put("COL_C", i);
argArray[0] = String.valueOf(id);
- db.update("T1", cv, "_ID=?", argArray);
+ mDatabase.update("T1", cv, "_ID=?", argArray);
i++;
android.os.Trace.endSection();
}
}
- /**
- * This test measures a multi-threaded read-write environment where there are 2 readers and
- * 1 writer in the database using WAL journal mode and NORMAL syncMode.
- */
- @Test
- public void testMultithreadedReadWriteWithWalNormal() {
- recreateTestDatabase(SQLiteDatabase.JOURNAL_MODE_WAL, SQLiteDatabase.SYNC_MODE_NORMAL);
- insertT1TestDataSet();
-
- performMultithreadedReadWriteTest();
- }
-
private void performMultithreadedReadWriteTest() {
int totalBGIterations = 10000;
// Writer - Fixed iterations to avoid consuming cycles from mainloop benchmark iterations
@@ -555,4 +553,3 @@
createOrOpenTestDatabase(journalMode, syncMode);
}
}
-
diff --git a/apct-tests/perftests/permission/Android.bp b/apct-tests/perftests/permission/Android.bp
new file mode 100644
index 0000000..b80a6af
--- /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 0000000..fa29ad0
--- /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 0000000..07558de
--- /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 0000000..1ad20b6
--- /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 0000000..3bccefd
--- /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 0000000..13e67e3
--- /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 d940e38..b0f378d 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.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 @@
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 @@
}
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 @@
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 @@
}
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 @@
// 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 bdc2246..d39863c 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 @@
* @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 363197a..1686943 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -444,3 +444,12 @@
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 ce5f995..0000000
--- 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 bcfb68f..7ae3224 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -63,6 +63,7 @@
":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 @@
"-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 ef1fa60..74344cd 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -635,7 +635,6 @@
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 2668999..b975c55 100644
--- a/api/api.go
+++ b/api/api.go
@@ -31,7 +31,6 @@
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 @@
// 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 CombinedApis struct {
android.ModuleBase
+ android.DefaultableModuleBase
properties CombinedApisProperties
}
@@ -74,6 +74,7 @@
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 @@
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 @@
}
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 e7361fe..b6e4e0d 100644
--- a/cmds/uinput/README.md
+++ b/cmds/uinput/README.md
@@ -7,11 +7,23 @@
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)
-Input commands should be in JSON format, though the parser is in [lenient mode] to allow comments,
+`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
+
+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 @@
[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 @@
[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 @@
[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 @@
}
```
-### `inject`
+#### `inject`
Send an array of uinput event packets to the uinput device
@@ -190,7 +202,7 @@
}
```
-### `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 e0b224e..46c8f82 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -49,6 +49,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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;
@@ -18617,6 +18623,7 @@
}
public final class SyncFence implements java.lang.AutoCloseable android.os.Parcelable {
+ ctor @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public SyncFence(@NonNull android.hardware.SyncFence);
method public boolean await(@NonNull java.time.Duration);
method public boolean awaitForever();
method public void close();
@@ -18673,6 +18680,7 @@
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();
@@ -18720,6 +18728,7 @@
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);
@@ -18743,6 +18752,43 @@
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 {
@@ -19732,7 +19778,7 @@
@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 {
@@ -28746,460 +28792,6 @@
}
-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 {
@@ -33399,7 +32991,7 @@
@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
}
@@ -33409,6 +33001,7 @@
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();
@@ -33910,7 +33503,6 @@
@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();
@@ -33993,8 +33585,8 @@
}
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[]);
@@ -41549,6 +41141,8 @@
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";
@@ -45340,7 +44934,7 @@
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();
@@ -47292,6 +46886,7 @@
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();
@@ -51798,6 +51393,7 @@
public static class SurfaceControl.Transaction implements java.io.Closeable android.os.Parcelable {
ctor public SurfaceControl.Transaction();
method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction addTransactionCompletedListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.SurfaceControl.TransactionStats>);
method public void apply();
method @NonNull public android.view.SurfaceControl.Transaction clearFrameRate(@NonNull android.view.SurfaceControl);
method @NonNull public android.view.SurfaceControl.Transaction clearTrustedPresentationCallback(@NonNull android.view.SurfaceControl);
@@ -51814,9 +51410,11 @@
method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
method @NonNull public android.view.SurfaceControl.Transaction setDamageRegion(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Region);
method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setDesiredPresentTime(long);
method @NonNull public android.view.SurfaceControl.Transaction setExtendedRangeBrightness(@NonNull android.view.SurfaceControl, float, float);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int);
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long);
method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
@@ -51832,10 +51430,19 @@
method public void onTransactionCommitted();
}
+ @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public static final class SurfaceControl.TransactionStats {
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") public long getLatchTime();
+ method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.hardware.SyncFence getPresentFence();
+ }
+
public static final class SurfaceControl.TrustedPresentationThresholds {
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();
@@ -53959,10 +53566,13 @@
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";
@@ -53975,6 +53585,8 @@
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";
@@ -56489,6 +56101,7 @@
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 f331e7f..162f54c 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -181,12 +181,6 @@
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 @@
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 c1b9f64..24b9233 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -319,11 +319,6 @@
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 a6a948c..a2179bc 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -235,14 +235,6 @@
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 @@
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 @@
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 b58c822..3c7c0d6 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -190,22 +190,6 @@
}
-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 9077d02..bd4ecf2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -475,6 +475,7 @@
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 @@
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 @@
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);
}
@@ -5747,7 +5751,7 @@
method public void addOnCompleteListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.OnCompleteListener);
method public void addOnCompleteListener(@NonNull android.hardware.radio.ProgramList.OnCompleteListener);
method public void close();
- method @Deprecated @Nullable public android.hardware.radio.RadioManager.ProgramInfo get(@NonNull android.hardware.radio.ProgramSelector.Identifier);
+ method @Nullable public android.hardware.radio.RadioManager.ProgramInfo get(@NonNull android.hardware.radio.ProgramSelector.Identifier);
method @FlaggedApi("android.hardware.radio.hd_radio_improved") @NonNull public java.util.List<android.hardware.radio.RadioManager.ProgramInfo> getProgramInfos(@NonNull android.hardware.radio.ProgramSelector.Identifier);
method public void registerListCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.radio.ProgramList.ListCallback);
method public void registerListCallback(@NonNull android.hardware.radio.ProgramList.ListCallback);
@@ -5799,7 +5803,7 @@
field @Deprecated public static final int IDENTIFIER_TYPE_DAB_SIDECC = 5; // 0x5
field @Deprecated public static final int IDENTIFIER_TYPE_DAB_SID_EXT = 5; // 0x5
field public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10; // 0xa
- field @Deprecated public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
+ field public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11; // 0xb
field public static final int IDENTIFIER_TYPE_DRMO_SERVICE_ID = 9; // 0x9
field public static final int IDENTIFIER_TYPE_HD_STATION_ID_EXT = 3; // 0x3
field @FlaggedApi("android.hardware.radio.hd_radio_improved") public static final int IDENTIFIER_TYPE_HD_STATION_LOCATION = 15; // 0xf
@@ -5807,8 +5811,8 @@
field @Deprecated public static final int IDENTIFIER_TYPE_HD_SUBCHANNEL = 4; // 0x4
field public static final int IDENTIFIER_TYPE_INVALID = 0; // 0x0
field public static final int IDENTIFIER_TYPE_RDS_PI = 2; // 0x2
- field @Deprecated public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
- field @Deprecated public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
+ field public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13; // 0xd
+ field public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12; // 0xc
field public static final int IDENTIFIER_TYPE_VENDOR_END = 1999; // 0x7cf
field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_END = 1999; // 0x7cf
field @Deprecated public static final int IDENTIFIER_TYPE_VENDOR_PRIMARY_START = 1000; // 0x3e8
@@ -5861,7 +5865,7 @@
field public static final int CONFIG_DAB_DAB_SOFT_LINKING = 8; // 0x8
field public static final int CONFIG_DAB_FM_LINKING = 7; // 0x7
field public static final int CONFIG_DAB_FM_SOFT_LINKING = 9; // 0x9
- field @Deprecated public static final int CONFIG_FORCE_ANALOG = 2; // 0x2
+ field public static final int CONFIG_FORCE_ANALOG = 2; // 0x2
field @FlaggedApi("android.hardware.radio.hd_radio_improved") public static final int CONFIG_FORCE_ANALOG_AM = 11; // 0xb
field @FlaggedApi("android.hardware.radio.hd_radio_improved") public static final int CONFIG_FORCE_ANALOG_FM = 10; // 0xa
field public static final int CONFIG_FORCE_DIGITAL = 3; // 0x3
@@ -9875,49 +9879,6 @@
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
@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 @@
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 @@
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 b2a28b2..6c83fd0 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -239,14 +239,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 51b8a11..bbfa0ec 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -142,17 +142,6 @@
}
-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 2e22071..bbe03a3 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3735,6 +3735,7 @@
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 fb1e16a..eba500d 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -14,20 +14,12 @@
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/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index b4a6955..845a346 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1311,8 +1311,9 @@
if (!node.mEnded) {
float durationScale = ValueAnimator.getDurationScale();
durationScale = durationScale == 0 ? 1 : durationScale;
- node.mEnded = node.mAnimation.pulseAnimationFrame(
- (long) (animPlayTime * durationScale));
+ if (node.mAnimation.pulseAnimationFrame((long) (animPlayTime * durationScale))) {
+ node.mEnded = true;
+ }
}
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 1e1f155..5840f02 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -25,8 +25,6 @@
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 @@
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 @@
*/
@Nullable
public Object getTarget() {
- return mTarget == null ? null : mTarget.get();
+ return mTarget;
}
@Override
@@ -929,7 +923,7 @@
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 @@
@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 f9583d2..2103055 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1177,23 +1177,12 @@
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 @@
}
/**
- * 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 0000000..3f73da2
--- /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 b5c66ff..f94987e 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 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 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 @@
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 @@
//
// 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 @@
EVENT_COUGH,
EVENT_SNORE,
EVENT_BACK_DOUBLE_TAP,
+ EVENT_HEART_RATE,
EVENT_VENDOR_WEARABLE_START
})
@Retention(RetentionPolicy.SOURCE)
@@ -209,6 +236,8 @@
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 @@
@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 @@
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 @@
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 @@
"endTime = " + mEndTime + ", " +
"confidenceLevel = " + mConfidenceLevel + ", " +
"densityLevel = " + mDensityLevel + ", " +
- "vendorData = " + mVendorData +
+ "vendorData = " + mVendorData + ", " +
+ "ratePerMinute = " + mRatePerMinute +
" }";
}
@@ -380,6 +426,7 @@
dest.writeInt(mConfidenceLevel);
dest.writeInt(mDensityLevel);
dest.writeTypedObject(mVendorData, flags);
+ dest.writeInt(mRatePerMinute);
}
@Override
@@ -399,6 +446,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
@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 6371871..a41cb1f 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -239,7 +239,7 @@
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 073e2d7..497eaf0 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 4cf9fca..6204edc 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -19,6 +19,7 @@
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.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 @@
}
}
+ /**
+ * 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 e56e53a..1a80cac2 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 @@
/** @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 @@
this.widgetFeatures = in.readInt();
this.descriptionRes = in.readInt();
this.isExtendedFromAppWidgetProvider = in.readBoolean();
+ if (generatedPreviews()) {
+ generatedPreviewCategories = in.readInt();
+ }
}
/**
@@ -515,6 +536,9 @@
out.writeInt(this.widgetFeatures);
out.writeInt(this.descriptionRes);
out.writeBoolean(this.isExtendedFromAppWidgetProvider);
+ if (generatedPreviews()) {
+ out.writeInt(this.generatedPreviewCategories);
+ }
}
@Override
@@ -545,6 +569,9 @@
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 c7a75ed..e9b94c9 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -41,6 +41,7 @@
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 @@
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 @@
!= 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 90c3d04..a37408b 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -4,6 +4,7 @@
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/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index f0a8996..a8dba51 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -382,10 +382,10 @@
* start it unless initiated by a user interaction (typically launching its icon
* from the launcher, could also include user actions like adding it as an app widget,
* selecting it as a live wallpaper, selecting it as a keyboard, etc). Stopped
- * applications will not receive broadcasts unless the sender specifies
+ * applications will not receive implicit broadcasts unless the sender specifies
* {@link android.content.Intent#FLAG_INCLUDE_STOPPED_PACKAGES}.
*
- * <p>Applications should avoid launching activies, binding to or starting services, or
+ * <p>Applications should avoid launching activities, binding to or starting services, or
* otherwise causing a stopped application to run unless initiated by the user.
*
* <p>An app can also return to the stopped state by a "force stop".
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 9e553db..de33fa8 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -89,6 +89,15 @@
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 ae46c027..2b378b1 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -101,6 +101,14 @@
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 c7797c7..1036865 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -70,4 +70,11 @@
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 40650d0..0ac5f6c 100644
--- a/core/java/android/credentials/GetCandidateCredentialsException.java
+++ b/core/java/android/credentials/GetCandidateCredentialsException.java
@@ -46,6 +46,17 @@
"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/SyncFence.java b/core/java/android/hardware/SyncFence.java
index d6052cd..c2440fb 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -16,6 +16,7 @@
package android.hardware;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.media.Image;
import android.media.ImageWriter;
@@ -26,6 +27,8 @@
import android.os.Parcelable;
import android.os.SystemClock;
+import com.android.window.flags.Flags;
+
import libcore.util.NativeAllocationRegistry;
import java.io.FileDescriptor;
@@ -121,6 +124,19 @@
}
}
+ /**
+ * Creates a copy of the SyncFence from an existing one.
+ * Both fences must be closed() independently.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public SyncFence(@NonNull SyncFence other) {
+ this(other.mNativePtr);
+
+ if (mNativePtr != 0) {
+ nIncRef(mNativePtr);
+ }
+ }
+
private SyncFence() {
mCloser = () -> {};
}
@@ -312,4 +328,5 @@
private static native int nGetFd(long nPtr);
private static native boolean nWait(long nPtr, long timeout);
private static native long nGetSignalTime(long nPtr);
+ private static native void nIncRef(long nPtr);
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 8c1ea5f..a0f4d8d 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -22,6 +22,7 @@
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 @@
/**
* 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 @@
}
/**
+ * 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 @@
}
/**
+ * 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/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/core/java/android/hardware/biometrics/PromptContentListItem.java
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to core/java/android/hardware/biometrics/PromptContentListItem.java
index 7b9634a..fa3783d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
+++ b/core/java/android/hardware/biometrics/PromptContentListItem.java
@@ -14,9 +14,16 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package android.hardware.biometrics;
-import com.android.systemui.kosmos.Kosmos
+import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT;
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 0000000..c31f8a6
--- /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 0000000..15271f0
--- /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 0000000..d72a758
--- /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/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/core/java/android/hardware/biometrics/PromptContentView.java
similarity index 65%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to core/java/android/hardware/biometrics/PromptContentView.java
index 7b9634a..ff9313e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
+++ b/core/java/android/hardware/biometrics/PromptContentView.java
@@ -14,9 +14,15 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package android.hardware.biometrics;
-import com.android.systemui.kosmos.Kosmos
+import static android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT;
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 0000000..43b965b
--- /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 24cfd164..c73ebd4 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -35,6 +35,7 @@
@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 @@
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 @@
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 @@
mDescription = description;
}
+ public void setContentView(PromptContentView view) {
+ mContentView = (PromptContentViewParcelable) view;
+ }
+
public void setDeviceCredentialTitle(CharSequence deviceCredentialTitle) {
mDeviceCredentialTitle = deviceCredentialTitle;
}
@@ -257,6 +265,15 @@
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 0000000..f3cb189
--- /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 375fdb5..3ba8be4 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -21,3 +21,10 @@
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 3affb73..0cd1c8c 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.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 @@
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);
+
+ return true;
+ } else {
+ return false;
}
- setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_SAMPLES, intrinsicsArray);
- setBase(CaptureResult.STATISTICS_LENS_INTRINSIC_TIMESTAMPS, tsArray);
-
- return true;
}
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;
}
+ 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));
+ }
+
+ 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;
}
-
- 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));
- }
-
- 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;
}
private Capability[] getExtendedSceneModeCapabilities() {
diff --git a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
index 575cbfa..9a4ec5c 100644
--- a/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
+++ b/core/java/android/hardware/camera2/params/LensIntrinsicsSample.java
@@ -37,16 +37,18 @@
* 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 @@
/**
* 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 134a510..8f0e0c9 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1831,15 +1831,6 @@
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/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index c5167db..a3a2a2e 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -304,11 +304,7 @@
*
* @param id primary identifier of a program to fetch
* @return the program info, or null if there is no such program on the list
- *
- * @deprecated Use {@link #getProgramInfos(ProgramSelector.Identifier)} to get all programs
- * with the given primary identifier
*/
- @Deprecated
public @Nullable RadioManager.ProgramInfo get(@NonNull ProgramSelector.Identifier id) {
Map<UniqueProgramIdentifier, RadioManager.ProgramInfo> entries;
synchronized (mLock) {
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 7e5c141..4c95e02 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -312,20 +312,14 @@
public static final int IDENTIFIER_TYPE_DRMO_FREQUENCY = 10;
/**
* 1: AM, 2:FM
- * @deprecated use {@link #IDENTIFIER_TYPE_DRMO_FREQUENCY} instead
*/
- @Deprecated
public static final int IDENTIFIER_TYPE_DRMO_MODULATION = 11;
/**
* 32bit primary identifier for SiriusXM Satellite Radio.
- *
- * @deprecated SiriusXM Satellite Radio is not supported
*/
public static final int IDENTIFIER_TYPE_SXM_SERVICE_ID = 12;
/**
* 0-999 range
- *
- * @deprecated SiriusXM Satellite Radio is not supported
*/
public static final int IDENTIFIER_TYPE_SXM_CHANNEL = 13;
/**
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index f0f7e8a..41f21ef 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -166,12 +166,7 @@
* analog handover state managed from the HAL implementation side.
*
* <p>Some radio technologies may not support this, i.e. DAB.
- *
- * @deprecated Use {@link #CONFIG_FORCE_ANALOG_FM} instead. If {@link #CONFIG_FORCE_ANALOG_FM}
- * is supported in HAL, {@link RadioTuner#setConfigFlag} and {@link RadioTuner#isConfigFlagSet}
- * with CONFIG_FORCE_ANALOG will set/get the value of {@link #CONFIG_FORCE_ANALOG_FM}.
*/
- @Deprecated
public static final int CONFIG_FORCE_ANALOG = 2;
/**
* Forces the digital playback for the supporting radio technology.
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index 70cf973..83b7eda 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -80,8 +80,6 @@
* <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 @@
* <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 @@
"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 @@
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 6956916..7afd721 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -5,4 +5,18 @@
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/OWNERS b/core/java/android/nfc/OWNERS
deleted file mode 100644
index 35e9713..0000000
--- a/core/java/android/nfc/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48448
-include platform/packages/apps/Nfc:/OWNERS
diff --git a/core/java/android/nfc/TEST_MAPPING b/core/java/android/nfc/TEST_MAPPING
deleted file mode 100644
index 5b5ea37..0000000
--- a/core/java/android/nfc/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "presubmit": [
- {
- "name": "NfcManagerTests"
- },
- {
- "name": "CtsNfcTestCases"
- }
- ]
-}
diff --git a/core/java/android/os/AggregateBatteryConsumer.java b/core/java/android/os/AggregateBatteryConsumer.java
index c5f5614..67e2195 100644
--- a/core/java/android/os/AggregateBatteryConsumer.java
+++ b/core/java/android/os/AggregateBatteryConsumer.java
@@ -33,6 +33,7 @@
*
* {@hide}
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class AggregateBatteryConsumer extends BatteryConsumer {
static final int CONSUMER_TYPE_AGGREGATE = 0;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 1a0ce70..b68b94d 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -37,6 +37,7 @@
import android.service.batterystats.BatteryStatsServiceDumpHistoryProto;
import android.service.batterystats.BatteryStatsServiceDumpProto;
import android.telephony.CellSignalStrength;
+import android.telephony.ModemActivityInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.format.DateFormat;
@@ -83,6 +84,7 @@
* except where indicated otherwise.
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public abstract class BatteryStats {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -463,6 +465,7 @@
/**
* State for keeping track of long counting information.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static abstract class LongCounter {
/**
@@ -2724,12 +2727,6 @@
*/
public abstract int getMobileRadioActiveUnknownCount(int which);
- public static final int DATA_CONNECTION_OUT_OF_SERVICE = 0;
- public static final int DATA_CONNECTION_EMERGENCY_SERVICE =
- TelephonyManager.getAllNetworkTypes().length + 1;
- public static final int DATA_CONNECTION_OTHER = DATA_CONNECTION_EMERGENCY_SERVICE + 1;
-
-
static final String[] DATA_CONNECTION_NAMES = {
"oos", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A",
"1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte",
@@ -2737,9 +2734,28 @@
"emngcy", "other"
};
+ public static final int DATA_CONNECTION_OUT_OF_SERVICE = 0;
+ public static final int DATA_CONNECTION_EMERGENCY_SERVICE = getEmergencyNetworkConnectionType();
+ public static final int DATA_CONNECTION_OTHER = DATA_CONNECTION_EMERGENCY_SERVICE + 1;
+
@UnsupportedAppUsage
public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER + 1;
+ @android.ravenwood.annotation.RavenwoodReplace
+ private static int getEmergencyNetworkConnectionType() {
+ int count = TelephonyManager.getAllNetworkTypes().length;
+ if (DATA_CONNECTION_NAMES.length != count + 3) { // oos, emngcy, other
+ throw new IllegalStateException(
+ "DATA_CONNECTION_NAMES length does not match network type count. "
+ + "Expected: " + (count + 3) + ", actual:" + DATA_CONNECTION_NAMES.length);
+ }
+ return count + 1;
+ }
+
+ private static int getEmergencyNetworkConnectionType$ravenwood() {
+ return DATA_CONNECTION_NAMES.length - 2;
+ }
+
/**
* Returns the time in microseconds that the phone has been running with
* the given data connection.
@@ -9015,4 +9031,44 @@
(lhs, rhs) -> Double.compare(rhs.millisecondsPerPacket, lhs.millisecondsPerPacket));
return uidMobileRadioStats;
}
+
+ @android.ravenwood.annotation.RavenwoodReplace
+ @VisibleForTesting
+ protected static boolean isLowRamDevice() {
+ return ActivityManager.isLowRamDeviceStatic();
+ }
+
+ protected static boolean isLowRamDevice$ravenwood() {
+ return false;
+ }
+
+ @android.ravenwood.annotation.RavenwoodReplace
+ @VisibleForTesting
+ protected static int getCellSignalStrengthLevelCount() {
+ return CellSignalStrength.getNumSignalStrengthLevels();
+ }
+
+ protected static int getCellSignalStrengthLevelCount$ravenwood() {
+ return 5;
+ }
+
+ @android.ravenwood.annotation.RavenwoodReplace
+ @VisibleForTesting
+ protected static int getModemTxPowerLevelCount() {
+ return ModemActivityInfo.getNumTxPowerLevels();
+ }
+
+ protected static int getModemTxPowerLevelCount$ravenwood() {
+ return 5;
+ }
+
+ @android.ravenwood.annotation.RavenwoodReplace
+ @VisibleForTesting
+ protected static boolean isKernelStatsAvailable() {
+ return true;
+ }
+
+ protected static boolean isKernelStatsAvailable$ravenwood() {
+ return false;
+ }
}
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 511f464..90d82e7 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -56,6 +56,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class BatteryUsageStats implements Parcelable, Closeable {
/**
diff --git a/core/java/android/os/BatteryUsageStatsQuery.java b/core/java/android/os/BatteryUsageStatsQuery.java
index 32840d4..203ef47 100644
--- a/core/java/android/os/BatteryUsageStatsQuery.java
+++ b/core/java/android/os/BatteryUsageStatsQuery.java
@@ -28,6 +28,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class BatteryUsageStatsQuery implements Parcelable {
@NonNull
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c60f949..fbec518 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -57,6 +57,7 @@
@UnsupportedAppUsage
Message mMessages;
+ private Message mLast;
@UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
@@ -66,6 +67,10 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
msg.next = p;
mMessages = msg;
needWake = mBlocked;
- } 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;
- }
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
+ if (p == null) {
+ mLast = mMessages;
}
- msg.next = p; // invariant: p == prev.next
- prev.next = msg;
+ } else {
+ // 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;
+ }
+ } 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;
+ }
+ }
+
+ if (msg.isAsynchronous()) {
+ mAsyncMessageCount++;
}
// We can assume mPtr != 0 because mQuitting is false.
@@ -692,10 +779,17 @@
&& (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 @@
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 @@
&& (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 @@
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 @@
&& (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 @@
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 @@
&& (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 @@
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 @@
&& (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 @@
&& (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 @@
p = n;
}
mMessages = null;
+ mLast = null;
+ mAsyncMessageCount = 0;
}
private void removeAllFutureMessagesLocked() {
@@ -911,9 +1078,14 @@
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 37bde3d..746278f 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -204,7 +204,7 @@
}
/**
- * 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/PowerComponents.java b/core/java/android/os/PowerComponents.java
index 9c11ad4..164e265 100644
--- a/core/java/android/os/PowerComponents.java
+++ b/core/java/android/os/PowerComponents.java
@@ -40,6 +40,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
class PowerComponents {
private final BatteryConsumer.BatteryConsumerData mData;
diff --git a/core/java/android/os/PowerMonitorReadings.java b/core/java/android/os/PowerMonitorReadings.java
index bb677d5..a0ab066 100644
--- a/core/java/android/os/PowerMonitorReadings.java
+++ b/core/java/android/os/PowerMonitorReadings.java
@@ -71,7 +71,7 @@
*/
@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 f952fcf..dd0436c 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -19,6 +19,7 @@
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 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 @@
@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/UidBatteryConsumer.java b/core/java/android/os/UidBatteryConsumer.java
index 3eea94e..53af838 100644
--- a/core/java/android/os/UidBatteryConsumer.java
+++ b/core/java/android/os/UidBatteryConsumer.java
@@ -37,6 +37,7 @@
*
* @hide
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public final class UidBatteryConsumer extends BatteryConsumer {
static final int CONSUMER_TYPE_UID = 1;
@@ -223,6 +224,7 @@
/**
* Builder for UidBatteryConsumer.
*/
+ @android.ravenwood.annotation.RavenwoodKeepWholeClass
public static final class Builder extends BaseBuilder<Builder> {
private static final String PACKAGE_NAME_UNINITIALIZED = "";
private final BatteryStats.Uid mBatteryStatsUid;
diff --git a/core/java/android/os/WorkDuration.java b/core/java/android/os/WorkDuration.java
index 4fdc34f..2ebcd83 100644
--- a/core/java/android/os/WorkDuration.java
+++ b/core/java/android/os/WorkDuration.java
@@ -26,7 +26,7 @@
* 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 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index c14810b..f3496e7 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -425,6 +425,8 @@
throw new ZygoteStartFailedEx("Embedded newlines not allowed");
} else if (arg.indexOf('\r') >= 0) {
throw new ZygoteStartFailedEx("Embedded carriage returns not allowed");
+ } else if (arg.indexOf('\u0000') >= 0) {
+ throw new ZygoteStartFailedEx("Embedded nulls not allowed");
}
}
@@ -965,6 +967,14 @@
return true;
}
+ for (/* NonNull */ String s : mApiDenylistExemptions) {
+ // indexOf() is intrinsified and faster than contains().
+ if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) {
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character");
+ mApiDenylistExemptions = Collections.emptyList();
+ return false;
+ }
+ }
try {
state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
state.mZygoteOutputWriter.newLine();
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index d646146..0db90bf 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -98,3 +98,11 @@
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 2d53341..322a8e6 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -25,8 +25,8 @@
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 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 @@
* (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 @@
}
}
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 @@
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 @@
* 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 @@
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/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 3ecf74e..54ed73c 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -134,16 +134,16 @@
@EnforcePermission("MOUNT_UNMOUNT_FILESYSTEMS")
void setDebugFlags(int flags, int mask) = 60;
@EnforcePermission("STORAGE_INTERNAL")
- void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) = 61;
+ void createUserStorageKeys(int userId, boolean ephemeral) = 61;
@EnforcePermission("STORAGE_INTERNAL")
void destroyUserStorageKeys(int userId) = 62;
@EnforcePermission("STORAGE_INTERNAL")
- void unlockCeStorage(int userId, int serialNumber, in byte[] secret) = 63;
+ void unlockCeStorage(int userId, in byte[] secret) = 63;
@EnforcePermission("STORAGE_INTERNAL")
void lockCeStorage(int userId) = 64;
boolean isCeStorageUnlocked(int userId) = 65;
@EnforcePermission("STORAGE_INTERNAL")
- void prepareUserStorage(in String volumeUuid, int userId, int serialNumber, int flags) = 66;
+ void prepareUserStorage(in String volumeUuid, int userId, int flags) = 66;
@EnforcePermission("STORAGE_INTERNAL")
void destroyUserStorage(in String volumeUuid, int userId, int flags) = 67;
@EnforcePermission("STORAGE_INTERNAL")
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 78a12f7..9587db1 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1602,14 +1602,13 @@
* This is only intended to be called by UserManagerService, as part of creating a user.
*
* @param userId ID of the user
- * @param serialNumber serial number of the user
* @param ephemeral whether the user is ephemeral
* @throws RuntimeException on error. The user's keys already existing is considered an error.
* @hide
*/
- public void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) {
+ public void createUserStorageKeys(int userId, boolean ephemeral) {
try {
- mStorageManager.createUserStorageKeys(userId, serialNumber, ephemeral);
+ mStorageManager.createUserStorageKeys(userId, ephemeral);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1653,9 +1652,9 @@
}
/** {@hide} */
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
+ public void prepareUserStorage(String volumeUuid, int userId, int flags) {
try {
- mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
+ mStorageManager.prepareUserStorage(volumeUuid, userId, flags);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index fae7cb3..60143cc 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -71,3 +71,10 @@
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 e8da0d9..f974ef4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3622,11 +3622,11 @@
}
if (names.length > 0) {
for (String name : names) {
- String value = mValues.get(name);
- if (value != null) {
+ // mValues can contain "null" values, need to use containsKey.
+ if (mValues.containsKey(name)) {
keyValues.put(
name.substring(substringLength),
- value);
+ mValues.get(name));
}
}
} else {
@@ -3700,11 +3700,11 @@
// Only the flags requested by the caller
if (names.length > 0) {
for (String name : names) {
- String value = flagsToValues.get(name);
- if (value != null) {
+ // flagsToValues can contain "null" values, need to use containsKey.
+ if (flagsToValues.containsKey(name)) {
keyValues.put(
name.substring(substringLength),
- value);
+ flagsToValues.get(name));
}
}
} else {
@@ -10158,8 +10158,12 @@
/**
* 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";
@@ -12176,6 +12180,36 @@
*/
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.
@@ -13442,6 +13476,16 @@
@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
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7d9c0a3..2d657c2 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -445,6 +445,19 @@
}
/**
+ * 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 92c516c..7658af5 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -42,6 +42,7 @@
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 @@
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 45a0c20..54248be 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -64,6 +64,7 @@
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 @@
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 @@
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 @@
@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 @@
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 @@
}
}
+ 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 @@
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 @@
}
}
+ 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 @@
} 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 @@
&& 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 @@
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 @@
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 @@
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 @@
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 @@
}
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 String iconResName;
public boolean allowManualInvocation;
public int userModifiedFields;
+ @Nullable public Instant deletionInstant; // Only set on deleted rules.
public ZenRule() { }
@@ -2031,6 +2095,9 @@
triggerDescription = source.readString();
type = source.readInt();
userModifiedFields = source.readInt();
+ if (source.readInt() == 1) {
+ deletionInstant = Instant.ofEpochMilli(source.readLong());
+ }
}
}
@@ -2091,6 +2158,12 @@
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 @@
.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 @@
&& 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 @@
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 8902368..91ef11c 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -30,6 +30,11 @@
/**
* 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 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 @@
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 a2ade6a..3008b8d 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -21,3 +21,11 @@
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 073e2d7..eca48b7 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 118d028..1ca7ac7 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 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 0000000..fd80127
--- /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 4c81888..a6d3bb4 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -454,7 +454,7 @@
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 @@
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 c9906cc..eca848a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -18,6 +18,7 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
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 f9abec0..135935c 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -76,6 +76,21 @@
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 @@
// 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 @@
* @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 @@
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 @@
return Math.signum(w) * boundsWidth;
}
} else {
- return measure(mLen, false, fmi, drawBounds);
+ return measure(mLen, false, fmi, drawBounds, lineInfo);
}
}
@@ -407,12 +424,13 @@
* 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 @@
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 @@
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 @@
}
/**
- * @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 @@
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 @@
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 @@
* @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 @@
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 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
* @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 @@
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 @@
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 @@
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 @@
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 a74cbe4..f0e673b 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -378,6 +378,13 @@
}
/**
+ * @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 9bf43a3..1d81be1 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -370,4 +370,14 @@
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/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b957b31..674f22c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -28,6 +28,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -71,6 +72,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.internal.util.VirtualRefBasePtr;
+import com.android.window.flags.Flags;
import dalvik.system.CloseGuard;
@@ -277,6 +279,8 @@
private static native int nativeGetLayerId(long nativeObject);
private static native void nativeAddTransactionCommittedListener(long nativeObject,
TransactionCommittedListener listener);
+ private static native void nativeAddTransactionCompletedListener(long nativeObject,
+ Consumer<TransactionStats> listener);
private static native void nativeSanitize(long transactionObject, int pid, int uid);
private static native void nativeSetDestinationFrame(long transactionObj, long nativeObject,
int l, int t, int r, int b);
@@ -290,6 +294,10 @@
private static native void nativeClearTrustedPresentationCallback(long transactionObj,
long nativeObject);
private static native StalledTransactionInfo nativeGetStalledTransactionInfo(int pid);
+ private static native void nativeSetDesiredPresentTime(long transactionObj,
+ long desiredPresentTime);
+ private static native void nativeSetFrameTimeline(long transactionObj,
+ long vsyncId);
/**
* Transforms that can be applied to buffers as they are displayed to a window.
@@ -2550,6 +2558,50 @@
}
/**
+ * Transaction stats given to the listener registered in
+ * {@link SurfaceControl.Transaction#addTransactionCompletedListener}
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public static final class TransactionStats {
+ private long mLatchTime;
+ private SyncFence mSyncFence;
+
+ // called from native
+ private TransactionStats(long latchTime, long presentFencePtr) {
+ mLatchTime = latchTime;
+ mSyncFence = new SyncFence(presentFencePtr);
+ }
+
+ /**
+ * Close the TransactionStats. Called by the framework when the listener returns.
+ * @hide
+ */
+ public void close() {
+ mSyncFence.close();
+ }
+
+ /**
+ * Returns the timestamp of when the frame was latched by the framework and queued for
+ * presentation.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public long getLatchTime() {
+ return mLatchTime;
+ }
+
+ /**
+ * Returns a new SyncFence that signals when the transaction has been presented.
+ * The caller takes ownership of the fence and is responsible for closing
+ * it by calling {@link SyncFence#close}.
+ * If a device does not support present fences, an empty fence will be returned.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ public @NonNull SyncFence getPresentFence() {
+ return new SyncFence(mSyncFence);
+ }
+ };
+
+ /**
* Threshold values that are sent with
* {@link Transaction#setTrustedPresentationCallback(SurfaceControl,
* TrustedPresentationThresholds, Executor, Consumer)}
@@ -4185,12 +4237,35 @@
}
/**
- * Sets the frame timeline vsync id received from choreographer
- * {@link Choreographer#getVsyncId()} that corresponds to the transaction submitted on that
- * surface control.
+ * Sets the frame timeline to use in SurfaceFlinger.
*
- * @hide
+ * A frame timeline should be chosen based on the frame deadline the application
+ * can meet when rendering the frame and the application's desired presentation time.
+ * By setting a frame timeline, SurfaceFlinger tries to present the frame at the
+ * corresponding expected presentation time.
+ *
+ * To receive frame timelines, a callback must be posted to Choreographer using
+ * {@link Choreographer#postVsyncCallback} The vsyncId can then be extracted from the
+ * {@link Choreographer.FrameTimeline#getVsyncId}.
+ *
+ * @param vsyncId The vsync ID received from Choreographer, setting the frame's
+ * presentation target to the corresponding expected presentation time
+ * and deadline from the frame to be rendered. A stale or invalid value
+ * will be ignored.
+ *
*/
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction setFrameTimeline(long vsyncId) {
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ nativeSetFrameTimelineVsync(mNativeObject, vsyncId);
+ return this;
+ }
+
+ /** @hide */
@NonNull
public Transaction setFrameTimelineVsync(long frameTimelineVsyncId) {
nativeSetFrameTimelineVsync(mNativeObject, frameTimelineVsyncId);
@@ -4207,6 +4282,9 @@
* to avoid dropping frames (overwriting transactions), and unable to use timestamps (Which
* provide a more efficient solution), then this method provides a method to pace your
* transaction application.
+ * The listener is invoked once the transaction is applied, and never again. Multiple
+ * listeners can be added to the same transaction, however the order the listeners will
+ * be called is not guaranteed.
*
* @param executor The executor that the callback should be invoked on.
* @param listener The callback that will be invoked when the transaction has been
@@ -4223,6 +4301,33 @@
}
/**
+ * Request to add a TransactionCompletedListener.
+ *
+ * The listener is invoked when transaction is presented, and never again. Multiple
+ * listeners can be added to the same transaction, however the order the listeners will
+ * be called is not guaranteed.
+ *
+ * @param executor The executor that the callback should be invoked on.
+ * @param listener The callback that will be invoked when the transaction has been
+ * completed.
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction addTransactionCompletedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TransactionStats> listener) {
+
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ Consumer<TransactionStats> listenerInner = stats -> executor.execute(
+ () -> listener.andThen(TransactionStats::close).accept(stats));
+ nativeAddTransactionCompletedListener(mNativeObject, listenerInner);
+ return this;
+ }
+
+ /**
* Sets a callback to receive feedback about the presentation of a {@link SurfaceControl}.
* When the {@link SurfaceControl} is presented according to the passed in
* {@link TrustedPresentationThresholds}, it is said to "enter the state", and receives the
@@ -4321,6 +4426,30 @@
}
/**
+ * Specifies a desiredPresentTime for the transaction. The framework will try to present
+ * the transaction at or after the time specified.
+ *
+ * Transactions will not be presented until all of their acquire fences have signaled even
+ * if the app requests an earlier present time.
+ *
+ * If an earlier transaction has a desired present time of x, and a later transaction has
+ * a desired present time that is before x, the later transaction will not preempt the
+ * earlier transaction.
+ *
+ * @param desiredPresentTime The desired time (in CLOCK_MONOTONIC) for the transaction.
+ * @return This transaction
+ */
+ @FlaggedApi(Flags.FLAG_SDK_DESIRED_PRESENT_TIME)
+ @NonNull
+ public Transaction setDesiredPresentTime(long desiredPresentTime) {
+ if (!Flags.sdkDesiredPresentTime()) {
+ Log.w(TAG, "addTransactionCompletedListener was called but flag is disabled");
+ return this;
+ }
+ nativeSetDesiredPresentTime(mNativeObject, desiredPresentTime);
+ return this;
+ }
+ /**
* Writes the transaction to parcel, clearing the transaction as if it had been applied so
* it can be used to store future transactions. It's the responsibility of the parcel
* reader to apply the original transaction.
diff --git a/core/java/android/view/SurfaceControlInputReceiver.java b/core/java/android/view/SurfaceControlInputReceiver.java
new file mode 100644
index 0000000..81e4448
--- /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 2b99e1e..257ecc5 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -33170,6 +33170,10 @@
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 350876c..c66f3c8 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 @@
}
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 @@
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 @@
} 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 d8fa415..42355bb 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -109,6 +109,7 @@
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 @@
* 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 @@
* 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 @@
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 f1e4061..8d40f9a 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.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.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 @@
private final TrustedPresentationListener mTrustedPresentationListener =
new TrustedPresentationListener();
+ private final ConcurrentHashMap<IBinder, InputEventReceiver> mSurfaceControlInputReceivers =
+ new ConcurrentHashMap<>();
+
private WindowManagerGlobal() {
}
@@ -808,6 +816,74 @@
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 b4b1fde..aaf5fcc 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -32,6 +32,7 @@
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 @@
@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 d6ac562..b95e459 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -30,6 +30,7 @@
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 @@
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 48f8f1b..c7355c1 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 @@
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 70d8abe..57a3b76 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -109,6 +109,40 @@
}
/**
+ * 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/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index bb49679..dbeffc8 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1469,7 +1469,8 @@
if (infos.size() == 0) {
throw new IllegalArgumentException("No VirtualViewInfo found");
}
- if (isCredmanRequested(view) && mIsFillAndSaveDialogDisabledForCredentialManager) {
+ if (shouldSuppressDialogsForCredman(view)
+ && mIsFillAndSaveDialogDisabledForCredentialManager) {
if (sDebug) {
Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
+ view.getAutofillId().toString());
@@ -1493,7 +1494,7 @@
* @hide
*/
public void notifyViewEnteredForFillDialog(View v) {
- if (isCredmanRequested(v)
+ if (shouldSuppressDialogsForCredman(v)
&& mIsFillAndSaveDialogDisabledForCredentialManager) {
if (sDebug) {
Log.d(TAG, "Ignoring Fill Dialog request since important for credMan:"
@@ -3390,19 +3391,39 @@
}
}
- private boolean isCredmanRequested(View view) {
+ private boolean shouldSuppressDialogsForCredman(View view) {
if (view == null) {
return false;
}
+ // isCredential field indicates that the developer might be calling Credman, and we should
+ // suppress autofill dialogs. But it is not a good enough indicator that there is a valid
+ // credman option.
if (view.isCredential()) {
return true;
}
+ return containsAutofillHintPrefix(view, View.AUTOFILL_HINT_CREDENTIAL_MANAGER);
+ }
+
+ private boolean isCredmanRequested(View view) {
+ if (view == null) {
+ return false;
+ }
String[] hints = view.getAutofillHints();
if (hints == null) {
return false;
}
+ // if hint starts with 'credential=', then we assume that there is a valid
+ // credential option set by the client.
+ return containsAutofillHintPrefix(view, View.AUTOFILL_HINT_CREDENTIAL_MANAGER + "=");
+ }
+
+ private boolean containsAutofillHintPrefix(View view, String prefix) {
+ String[] hints = view.getAutofillHints();
+ if (hints == null) {
+ return false;
+ }
for (String hint : hints) {
- if (hint != null && hint.startsWith(View.AUTOFILL_HINT_CREDENTIAL_MANAGER)) {
+ if (hint != null && hint.startsWith(prefix)) {
return true;
}
}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index a74b06a..9f9b7b4 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 bb7677d6..ccc5dbb 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -47,3 +47,10 @@
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 ef50045..1d2f653 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 @@
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 @@
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 bdaad2b..473b814 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -47,6 +47,7 @@
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 @@
"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 56df493..3c3c846 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -63,4 +63,20 @@
description: "Enable trustedPresentationListener on windows public API"
is_fixed_read_only: true
bug: "278027319"
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "window_surfaces"
+ name: "sdk_desired_present_time"
+ description: "Feature flag for the new SDK API to set desired present time"
+ 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 f2bce9c..bb16ad2 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -72,7 +72,7 @@
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 4fe9aea..85bdbb9 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -80,5 +80,11 @@
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 e55c641..fab8984 100644
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -33,13 +33,14 @@
/**
* 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/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 1330e16..7a79e0f 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -977,11 +977,16 @@
/**
* @return true if there is more than 100MB free disk space left.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
private boolean hasFreeDiskSpace() {
final StatFs stats = new StatFs(mHistoryDir.getAbsolutePath());
return stats.getAvailableBytes() > MIN_FREE_SPACE;
}
+ private boolean hasFreeDiskSpace$ravenwood() {
+ return true;
+ }
+
@VisibleForTesting
public List<String> getFilesNames() {
List<String> names = new ArrayList<>();
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 2298cbd..ab982f5 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -50,6 +50,7 @@
* Customize the XML file for different devices.
* [hidden]
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class PowerProfile {
public static final String TAG = "PowerProfile";
@@ -321,6 +322,13 @@
private int mCpuPowerBracketCount;
@VisibleForTesting
+ public PowerProfile() {
+ synchronized (sLock) {
+ initLocked();
+ }
+ }
+
+ @VisibleForTesting
@UnsupportedAppUsage
public PowerProfile(Context context) {
this(context, false);
@@ -358,6 +366,10 @@
if (sPowerItemMap.size() == 0 && sPowerArrayMap.size() == 0) {
readPowerValuesFromXml(context, xmlId);
}
+ initLocked();
+ }
+
+ private void initLocked() {
initCpuClusters();
initCpuScalingPolicies();
initCpuPowerBrackets();
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 5d82d04..12aff1c 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.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 @@
.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 a1dd19a3..4ac542f8 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.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 @@
| 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/java/com/android/internal/power/ModemPowerProfile.java b/core/java/com/android/internal/power/ModemPowerProfile.java
index a555ae3..b15c10e 100644
--- a/core/java/com/android/internal/power/ModemPowerProfile.java
+++ b/core/java/com/android/internal/power/ModemPowerProfile.java
@@ -39,6 +39,7 @@
/**
* ModemPowerProfile for handling the modem element in the power_profile.xml
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class ModemPowerProfile {
private static final String TAG = "ModemPowerProfile";
diff --git a/core/jni/android_hardware_SyncFence.cpp b/core/jni/android_hardware_SyncFence.cpp
index b996653..6e94616 100644
--- a/core/jni/android_hardware_SyncFence.cpp
+++ b/core/jni/android_hardware_SyncFence.cpp
@@ -66,6 +66,10 @@
return fromJlong<Fence>(jPtr)->getSignalTime();
}
+static void SyncFence_incRef(JNIEnv*, jobject, jlong jPtr) {
+ fromJlong<Fence>(jPtr)->incStrong((void*)SyncFence_incRef);
+}
+
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -80,6 +84,7 @@
{ "nGetFd", "(J)I", (void*) SyncFence_getFd },
{ "nWait", "(JJ)Z", (void*) SyncFence_wait },
{ "nGetSignalTime", "(J)J", (void*) SyncFence_getSignalTime },
+ { "nIncRef", "(J)V", (void*) SyncFence_incRef },
};
// clang-format on
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index b651711..a5b2f65 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -96,8 +96,11 @@
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/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index db42246..55326da 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -231,6 +231,16 @@
static struct {
jclass clazz;
+ jmethodID accept;
+} gConsumerClassInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+} gTransactionStatsClassInfo;
+
+static struct {
+ jclass clazz;
jmethodID ctor;
jfieldID format;
jfieldID alphaInterpretation;
@@ -317,6 +327,52 @@
}
};
+class TransactionCompletedListenerWrapper {
+public:
+ explicit TransactionCompletedListenerWrapper(JNIEnv* env, jobject object) {
+ env->GetJavaVM(&mVm);
+ mTransactionCompletedListenerObject = env->NewGlobalRef(object);
+ LOG_ALWAYS_FATAL_IF(!mTransactionCompletedListenerObject, "Failed to make global ref");
+ }
+
+ ~TransactionCompletedListenerWrapper() {
+ getenv()->DeleteGlobalRef(mTransactionCompletedListenerObject);
+ }
+
+ void callback(nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& /*stats*/) {
+ JNIEnv* env = getenv();
+ // Adding a strong reference for java SyncFence
+ presentFence->incStrong(0);
+
+ jobject stats =
+ env->NewObject(gTransactionStatsClassInfo.clazz, gTransactionStatsClassInfo.ctor,
+ latchTime, presentFence.get());
+ env->CallVoidMethod(mTransactionCompletedListenerObject, gConsumerClassInfo.accept, stats);
+ env->DeleteLocalRef(stats);
+ DieIfException(env, "Uncaught exception in TransactionCompletedListener.");
+ }
+
+ static void transactionCallbackThunk(void* context, nsecs_t latchTime,
+ const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ TransactionCompletedListenerWrapper* listener =
+ reinterpret_cast<TransactionCompletedListenerWrapper*>(context);
+ listener->callback(latchTime, presentFence, stats);
+ delete listener;
+ }
+
+private:
+ jobject mTransactionCompletedListenerObject;
+ JavaVM* mVm;
+
+ JNIEnv* getenv() {
+ JNIEnv* env;
+ mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+ return env;
+ }
+};
+
class WindowInfosReportedListenerWrapper : public gui::BnWindowInfosReportedListener {
public:
explicit WindowInfosReportedListenerWrapper(JNIEnv* env, jobject listener) {
@@ -1879,10 +1935,16 @@
FrameTimelineInfo ftInfo;
ftInfo.vsyncId = frameTimelineVsyncId;
- ftInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID;
transaction->setFrameTimelineInfo(ftInfo);
}
+static void nativeSetDesiredPresentTime(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong desiredPresentTime) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ transaction->setDesiredPresentTime(desiredPresentTime);
+}
+
static void nativeAddTransactionCommittedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
jobject transactionCommittedListenerObject) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -1894,6 +1956,17 @@
context);
}
+static void nativeAddTransactionCompletedListener(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jobject transactionCompletedListenerObject) {
+ auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+
+ void* context =
+ new TransactionCompletedListenerWrapper(env, transactionCompletedListenerObject);
+ transaction->addTransactionCompletedCallback(TransactionCompletedListenerWrapper::
+ transactionCallbackThunk,
+ context);
+}
+
static void nativeSetTrustedPresentationCallback(JNIEnv* env, jclass clazz, jlong transactionObj,
jlong nativeObject,
jlong trustedPresentationCallbackObject,
@@ -2318,6 +2391,8 @@
(void*)nativeSurfaceFlushJankData },
{"nativeAddTransactionCommittedListener", "(JLandroid/view/SurfaceControl$TransactionCommittedListener;)V",
(void*) nativeAddTransactionCommittedListener },
+ {"nativeAddTransactionCompletedListener", "(JLjava/util/function/Consumer;)V",
+ (void*) nativeAddTransactionCompletedListener },
{"nativeSetTrustedPresentationCallback", "(JJJLandroid/view/SurfaceControl$TrustedPresentationThresholds;)V",
(void*) nativeSetTrustedPresentationCallback },
{"nativeClearTrustedPresentationCallback", "(JJ)V",
@@ -2337,6 +2412,8 @@
{"getNativeTrustedPresentationCallbackFinalizer", "()J", (void*)getNativeTrustedPresentationCallbackFinalizer },
{"nativeGetStalledTransactionInfo", "(I)Landroid/gui/StalledTransactionInfo;",
(void*) nativeGetStalledTransactionInfo },
+ {"nativeSetDesiredPresentTime", "(JJ)V",
+ (void*) nativeSetDesiredPresentTime },
// clang-format on
};
@@ -2539,6 +2616,16 @@
gTransactionCommittedListenerClassInfo.onTransactionCommitted =
GetMethodIDOrDie(env, transactionCommittedListenerClazz, "onTransactionCommitted",
"()V");
+ jclass consumerClazz = FindClassOrDie(env, "java/util/function/Consumer");
+ gConsumerClassInfo.clazz = MakeGlobalRefOrDie(env, consumerClazz);
+ gConsumerClassInfo.accept =
+ GetMethodIDOrDie(env, consumerClazz, "accept", "(Ljava/lang/Object;)V");
+
+ jclass transactionStatsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$TransactionStats");
+ gTransactionStatsClassInfo.clazz = MakeGlobalRefOrDie(env, transactionStatsClazz);
+ gTransactionStatsClassInfo.ctor =
+ GetMethodIDOrDie(env, gTransactionStatsClassInfo.clazz, "<init>", "(JJ)V");
jclass displayDecorationSupportClazz =
FindClassOrDie(env, "android/hardware/graphics/common/DisplayDecorationSupport");
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index db391f7..a854e36 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -18,6 +18,7 @@
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 @@
# 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 52e0124..b63021d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -397,6 +397,8 @@
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 ef6caef..5f3f641 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 8281462..b60bd63 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 ff7dee8..5a6ef3c 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 0cc49a5..136ad53 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 ddc2367..fa9e2d7 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 794e26a..d4df38e 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 8df8b87..e19a0b2 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 13801d0..515a6a3 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 e0e9b09..4689e32 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 cf8c64d..d615cbe 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 ef941e19f..f110a24 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 ec14677..d9744dd 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 e518de4..c72f07d 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 d3f8550..f72c0c2 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 514d695..e03592c 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 a392c0f..d9c9451 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 7498488..fd801b5 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 fd76ce5..bf9acc1 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 1f2ccce..662247e 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 d4fd01e..e7278d5 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 8a89ebd..51ab2ca 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 f6117cd..8686e19 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 406f879..8f57a07 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 afcc618..e814c96 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 2b9c555..feabc8f 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 eb71a7d..c661e95 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 8359bf6..9aad9fa6 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 8842ae8..7be3041 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 3b24230..f6e669c 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 703ed7c..98560f3 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 2e1f0e6..9d29201 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 336d998..084b956 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 ec5a77e..ca57b68 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 3bcd44b..2ccacff 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 603d7c6..9480cc5 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 7886280..50ef6a0 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 ddf60c1..804f131 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 3877ac4..c1ef0ea 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 eb2f3b2..c189218 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 a2d40af..7bb322c 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 dee1f1f..7b7f267 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 4cf61ac..fa2a798 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 7973f2a..ab51e6e 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 7e5e5b5..625ade1 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 cfc7730..a40a7f4 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 dcdfc80..cfa0983 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 49266a4..653de36 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 aefda2e..4733552 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 f17f02f..0f4e3f9 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 dbcf11f..fd8daac 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 68c0749..a001de3 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 97858ef2..16b5766 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 cd553a4..51752e3 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 90ffb21..599083c 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 fa5efa6..cd7d43b 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 f97e437..b77d86a 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 99dcae0..6dbeb40 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 f0d34a5..0bd0a59 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 bfde6c9..58ab2c2 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 d3901f7..c3e4134 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 e03679b..07a69e6 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 2888c5f..e29502a 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 7a3201f..cae02fc 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 2888c5f..e29502a 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 082fbb2..2beb190 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 8a03a6b..299e445 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 89ee9f9..e19231e 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 bbfefd1..c9508ba 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 e4e9a37..c459fdb 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 288d8bf..a62dddb 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 479a1db..048d826 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 a30aa0a..d10cbe6 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 9a063fb..8e1348f 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 23402f7..32fb6a4 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 30697b3..3f98b25 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 66ed053..81fa177 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 c83daa3..8009e0c 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 c2c8ec6..18f46ee 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 00139a6..88a3b2b 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 dc3ca47..267351a 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 23ef54c..d739e8b 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 22d9f06..15f7f8f 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 af30532..31acd9a 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 dec4705..91fdc94 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 769c274..3fe3061 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 2c8c046..4f6ef28 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 42f0b3f..d5ce2ad 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 8fae6db..6019524 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 806be94..5be29a6 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 17bb86a..7b5c49c 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 542e9d6..f285806 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/animation/AnimatorSetCallsTest.java b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
index 43266a5..cb3f99c 100644
--- a/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
+++ b/core/tests/coretests/src/android/animation/AnimatorSetCallsTest.java
@@ -17,6 +17,7 @@
package android.animation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.util.PollingCheck;
@@ -343,6 +344,20 @@
}
@Test
+ public void childAnimatorCancelsDuringUpdate_animatorSetIsEnded() throws Throwable {
+ mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ animation.cancel();
+ }
+ });
+ mActivity.runOnUiThread(() -> {
+ mSet1.start();
+ assertFalse(mSet1.isRunning());
+ });
+ }
+
+ @Test
public void reentrantStart() throws Throwable {
CountDownLatch latch = new CountDownLatch(3);
AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java
index bd5f809..e118c98d 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 @@
final String query = "--comment\nSELECT count(*) from t1";
+ database.beginTransactionReadOnly();
try {
for (int i = count; i > 0; i--) {
ticker.arriveAndAwaitAdvance();
@@ -268,6 +269,7 @@
} 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 bf56df1..0dec756 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertNotEquals;
import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
import androidx.test.filters.SmallTest;
@@ -362,4 +363,44 @@
// = 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 3162e6d..2d3e123 100644
--- a/core/tests/coretests/src/android/os/BuildTest.java
+++ b/core/tests/coretests/src/android/os/BuildTest.java
@@ -45,7 +45,8 @@
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 12a2844..a28bb69 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -195,9 +195,30 @@
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 @@
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 0000000..c70da6e
--- /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 34842a0..a31992c 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -50,11 +50,11 @@
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 @@
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 @@
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 @@
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 @@
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/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
index c9536b9..533b799 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -22,7 +22,6 @@
import android.os.BadParcelableException;
import android.os.Parcel;
-import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.filters.SmallTest;
@@ -34,7 +33,6 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
-@IgnoreUnderRavenwood(blockedBy = LongArrayMultiStateCounter.class)
public class LongArrayMultiStateCounterTest {
@Rule
public final RavenwoodRule mRavenwood = new RavenwoodRule();
diff --git a/core/tests/nfctests/OWNERS b/core/tests/nfctests/OWNERS
deleted file mode 100644
index 34b095c..0000000
--- 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 dcc9686..fbe1b8e 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 0000000..f0320c8
--- /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 0000000..52ed0bc
--- /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 f10cdb8..c5a2f98 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -65,6 +65,8 @@
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 @@
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 @@
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 @@
* @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 @@
}
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 @@
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 @@
* @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 @@
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 @@
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 @@
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 5ad144d..45540e0 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -175,3 +175,74 @@
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 0000000..f8f8338
--- /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 0000000..ffcd7d4
--- /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 0000000..36fe8ec
--- /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 0000000..7a0527c
--- /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 0000000..ea7c6ed
--- /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 0000000..20ee34a
--- /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 0000000..20ee34a
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTestsForDeviceless
@@ -0,0 +1 @@
+multivalentTests
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
index 681a52b..e04ab81 100644
--- a/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
+++ b/libs/WindowManager/Shell/res/layout/bubble_bar_expanded_view.xml
@@ -21,4 +21,9 @@
android:orientation="vertical"
android:id="@+id/bubble_bar_expanded_view">
+ <com.android.wm.shell.bubbles.bar.BubbleBarHandleView
+ android:id="@+id/bubble_bar_handle_view"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
</com.android.wm.shell.bubbles.bar.BubbleBarExpandedView>
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 06210ff..44ee561 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 @@
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 81d9638..bb433db 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 @@
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 @@
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
+ mPreviousNavigationType = mBackNavigationInfo.getType();
mBackNavigationInfo.onBackNavigationFinished(triggerBack);
mBackNavigationInfo = null;
}
@@ -983,7 +988,9 @@
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 80fc3a8..ac2a1c8 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 @@
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 896bcaf..e23e15f 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 @@
}
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 @@
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 470a825..ca28312 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 @@
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/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index d073f1d..66c0c96 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -70,7 +70,7 @@
private @Nullable Supplier<Rect> mLayerBoundsSupplier;
private @Nullable Listener mListener;
- private BubbleBarHandleView mHandleView = new BubbleBarHandleView(getContext());
+ private BubbleBarHandleView mHandleView;
private @Nullable TaskView mTaskView;
private @Nullable BubbleOverflowContainerView mOverflowView;
@@ -111,7 +111,7 @@
setElevation(getResources().getDimensionPixelSize(R.dimen.bubble_elevation));
mCaptionHeight = context.getResources().getDimensionPixelSize(
R.dimen.bubble_bar_expanded_view_caption_height);
- addView(mHandleView);
+ mHandleView = findViewById(R.id.bubble_bar_handle_view);
applyThemeAttrs();
setClipToOutline(true);
setOutlineProvider(new ViewOutlineProvider() {
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 a587bed..da1ca8d 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 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 @@
* 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.
+ * 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.
*/
- 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.
- */
- 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 @@
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 @@
}
/**
- * 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
+ * Takes existing indicator and animates it to bounds reflecting a new indicator type.
*/
- 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.
- */
- 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 @@
}
/**
- * 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 @@
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 @@
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));
- animator.setInterpolator(new DecelerateInterpolator());
- setupIndicatorAnimation(animator);
- return animator;
- }
-
- /**
- * Create animator for visual indicator of freeform transition
- *
- * @param view the view for this indicator
- * @param displayLayout information about the display the transitioning task is currently on
- */
- 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)));
- final VisualIndicatorAnimator animator = new VisualIndicatorAnimator(
view, startBounds, endBounds);
animator.setInterpolator(new DecelerateInterpolator());
- setupIndicatorAnimation(animator);
+ setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM);
return animator;
}
/**
+ * 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
+ */
+ 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, 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 @@
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 b1c43c1..4f5c39a 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.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 @@
*
* @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
+ syncQueue, taskInfo, displayController, context, taskSurface,
+ rootTaskDisplayAreaOrganizer)
}
- if (visualIndicator?.eventOutsideRange(inputCoordinate.x,
- taskBounds.top.toFloat()) == true) {
- releaseVisualIndicator()
- }
+ // Then, update the indicator type.
+ val indicator = visualIndicator ?: return
+ indicator.updateIndicatorType(PointF(inputX, taskTop))
}
/**
@@ -936,45 +938,6 @@
}
/**
- * 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 @@
}
/**
- * 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 89dcc4c..8e375a9 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 @@
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 bc1a575..5de8a9b 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 @@
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 0eb7c2d..a7843e2 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 @@
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 db84513..bf783e6 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 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 TransitionInfo subCopy(@NonNull TransitionInfo info,
+ private MixedTransition createMixedTransition(int type, IBinder transition) {
+ return new MixedTransition(type, transition, mPlayer, this, mPipHandler, mRecentsHandler,
+ mSplitHandler, mKeyguardHandler, mDesktopTasksController, mUnfoldHandler,
+ mActivityEmbeddingController);
+ }
+
+ 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 @@
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 @@
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 @@
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,
+ private static boolean animateEnterPipFromSplit(@NonNull final 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,
- @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 @@
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 @@
}
if (pipChange == null) {
// um, something probably went wrong.
- mActiveTransitions.remove(mixed);
return false;
}
final boolean isGoingHome = homeIsOpening;
@@ -630,13 +883,12 @@
--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 @@
// 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 @@
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 @@
}
}
// 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 @@
}
}
- 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 @@
// 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 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 @@
}
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 @@
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);
+ if (pipHandler != null) {
+ pipHandler.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;
- }
- 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 @@
@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 @@
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 @@
// 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 d7cb490..4aed7c4 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.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 @@
}
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 a5d2cd7..aabc1cf 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
@@ -502,7 +502,7 @@
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;
@@ -737,9 +737,9 @@
}
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/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 182a908..be77171 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 @@
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 6ebee73..0000000
--- 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 2f28363..77800a3 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -31,6 +31,12 @@
],
}
+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 @@
"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 1a6a952..a1e7c2f 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 @@
{
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 @@
}
// 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 @@
-#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 6c3172a..d58c872 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -56,6 +56,7 @@
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 @@
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 bca57e9..b956fac 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -143,6 +143,15 @@
#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 @@
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 c156c46..72ddecc 100644
--- a/libs/hwui/aconfig/hwui_flags.aconfig
+++ b/libs/hwui/aconfig/hwui_flags.aconfig
@@ -22,6 +22,13 @@
}
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 80b6c03..e9f4b81c 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 @@
// 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 8f99990..ba65439 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -33,6 +33,8 @@
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 @@
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 @@
, 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 @@
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 @@
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 7552b56d..833069f 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -96,7 +96,7 @@
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 @@
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 61bc881..f8574ee 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -53,7 +53,7 @@
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 7cc4866..8315c4c 100644
--- a/libs/hwui/jni/Graphics.cpp
+++ b/libs/hwui/jni/Graphics.cpp
@@ -247,6 +247,9 @@
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 @@
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 @@
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 b9fff36..b0a1074 100644
--- a/libs/hwui/jni/GraphicsJNI.h
+++ b/libs/hwui/jni/GraphicsJNI.h
@@ -77,6 +77,8 @@
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 d84b73d..58d9d8b 100644
--- a/libs/hwui/jni/Paint.cpp
+++ b/libs/hwui/jni/Paint.cpp
@@ -114,7 +114,7 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
(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 234f42d..756b937 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 @@
/**
* 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 @@
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 4592711..777d1a2 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 @@
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 30d4612..eb4d494 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -269,13 +269,14 @@
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 c70a304..9911bfa 100644
--- a/libs/hwui/tests/unit/UnderlineTest.cpp
+++ b/libs/hwui/tests/unit/UnderlineTest.cpp
@@ -103,8 +103,9 @@
// 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 79b2155..660884a 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 ee2510f..0d5af50 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -19,6 +19,7 @@
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.emergency.EmergencyNumber;
import android.util.Log;
+import com.android.internal.telephony.flags.Flags;
+
import java.util.concurrent.TimeUnit;
/**
@@ -139,8 +142,20 @@
(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 89792c7..9616b5d 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -48,6 +48,7 @@
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 @@
* 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 @@
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 @@
new SystemRoutingController(
ProxyMediaRouter2Impl.getSystemSessionInfoImpl(
mMediaRouterService, clientPackageName));
+
mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user);
}
@@ -713,7 +719,7 @@
mImpl.transfer(
controller.getRoutingSessionInfo(),
route,
- android.os.Process.myUserHandle(),
+ Process.myUserHandle(),
mContext.getPackageName());
}
@@ -883,7 +889,7 @@
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 @@
}
}
- 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 @@
}
}
+ 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 @@
MediaRouter2::dispatchFilteredRoutesUpdatedOnHandler,
this,
mFilteredRoutes));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::dispatchControllerUpdatedIfNeededOnHandler,
+ this,
+ new HashMap<>(mRoutes)));
}
/**
@@ -1528,7 +1560,7 @@
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 @@
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 @@
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 @@
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 a7ec6c6..8ce1b6d 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -37,31 +37,41 @@
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 @@
*
* <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 @@
@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 262f5f1..096e8ad 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 @@
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 @@
// 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 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 cb9ac6f..1f187e8 100644
--- a/nfc-extras/Android.bp
+++ b/nfc-extras/Android.bp
@@ -23,9 +23,13 @@
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 bf9f47c..5d1404a 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -10,7 +10,15 @@
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 @@
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 @@
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 d802177..24c145f 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 0000000..ef9aab6
--- /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 d802177..5ebe911 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 0000000..f7f8ee3
--- /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 d802177..fb82b5d 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 d802177..40672a1 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 0000000..761c8e6
--- /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 d802177..c6eaa57 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 0000000..4cd652d
--- /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
similarity index 100%
rename from core/java/android/nfc/ApduList.aidl
rename to nfc/java/android/nfc/ApduList.aidl
diff --git a/core/java/android/nfc/ApduList.java b/nfc/java/android/nfc/ApduList.java
similarity index 100%
rename from core/java/android/nfc/ApduList.java
rename to nfc/java/android/nfc/ApduList.java
diff --git a/core/java/android/nfc/AvailableNfcAntenna.aidl b/nfc/java/android/nfc/AvailableNfcAntenna.aidl
similarity index 100%
rename from core/java/android/nfc/AvailableNfcAntenna.aidl
rename to nfc/java/android/nfc/AvailableNfcAntenna.aidl
diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java
similarity index 100%
rename from core/java/android/nfc/AvailableNfcAntenna.java
rename to nfc/java/android/nfc/AvailableNfcAntenna.java
diff --git a/core/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java
similarity index 100%
rename from core/java/android/nfc/Constants.java
rename to nfc/java/android/nfc/Constants.java
diff --git a/core/java/android/nfc/ErrorCodes.java b/nfc/java/android/nfc/ErrorCodes.java
similarity index 100%
rename from core/java/android/nfc/ErrorCodes.java
rename to nfc/java/android/nfc/ErrorCodes.java
diff --git a/core/java/android/nfc/FormatException.java b/nfc/java/android/nfc/FormatException.java
similarity index 100%
rename from core/java/android/nfc/FormatException.java
rename to nfc/java/android/nfc/FormatException.java
diff --git a/core/java/android/nfc/IAppCallback.aidl b/nfc/java/android/nfc/IAppCallback.aidl
similarity index 100%
rename from core/java/android/nfc/IAppCallback.aidl
rename to nfc/java/android/nfc/IAppCallback.aidl
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
similarity index 100%
rename from core/java/android/nfc/INfcAdapter.aidl
rename to nfc/java/android/nfc/INfcAdapter.aidl
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/nfc/java/android/nfc/INfcAdapterExtras.aidl
similarity index 100%
rename from core/java/android/nfc/INfcAdapterExtras.aidl
rename to nfc/java/android/nfc/INfcAdapterExtras.aidl
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
similarity index 100%
rename from core/java/android/nfc/INfcCardEmulation.aidl
rename to nfc/java/android/nfc/INfcCardEmulation.aidl
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
similarity index 100%
rename from core/java/android/nfc/INfcControllerAlwaysOnListener.aidl
rename to nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
diff --git a/core/java/android/nfc/INfcDta.aidl b/nfc/java/android/nfc/INfcDta.aidl
similarity index 100%
rename from core/java/android/nfc/INfcDta.aidl
rename to nfc/java/android/nfc/INfcDta.aidl
diff --git a/core/java/android/nfc/INfcFCardEmulation.aidl b/nfc/java/android/nfc/INfcFCardEmulation.aidl
similarity index 100%
rename from core/java/android/nfc/INfcFCardEmulation.aidl
rename to nfc/java/android/nfc/INfcFCardEmulation.aidl
diff --git a/core/java/android/nfc/INfcTag.aidl b/nfc/java/android/nfc/INfcTag.aidl
similarity index 100%
rename from core/java/android/nfc/INfcTag.aidl
rename to nfc/java/android/nfc/INfcTag.aidl
diff --git a/core/java/android/nfc/INfcUnlockHandler.aidl b/nfc/java/android/nfc/INfcUnlockHandler.aidl
similarity index 100%
rename from core/java/android/nfc/INfcUnlockHandler.aidl
rename to nfc/java/android/nfc/INfcUnlockHandler.aidl
diff --git a/core/java/android/nfc/INfcWlcStateListener.aidl b/nfc/java/android/nfc/INfcWlcStateListener.aidl
similarity index 100%
rename from core/java/android/nfc/INfcWlcStateListener.aidl
rename to nfc/java/android/nfc/INfcWlcStateListener.aidl
diff --git a/core/java/android/nfc/ITagRemovedCallback.aidl b/nfc/java/android/nfc/ITagRemovedCallback.aidl
similarity index 100%
rename from core/java/android/nfc/ITagRemovedCallback.aidl
rename to nfc/java/android/nfc/ITagRemovedCallback.aidl
diff --git a/core/java/android/nfc/NdefMessage.aidl b/nfc/java/android/nfc/NdefMessage.aidl
similarity index 100%
rename from core/java/android/nfc/NdefMessage.aidl
rename to nfc/java/android/nfc/NdefMessage.aidl
diff --git a/core/java/android/nfc/NdefMessage.java b/nfc/java/android/nfc/NdefMessage.java
similarity index 100%
rename from core/java/android/nfc/NdefMessage.java
rename to nfc/java/android/nfc/NdefMessage.java
diff --git a/core/java/android/nfc/NdefRecord.aidl b/nfc/java/android/nfc/NdefRecord.aidl
similarity index 100%
rename from core/java/android/nfc/NdefRecord.aidl
rename to nfc/java/android/nfc/NdefRecord.aidl
diff --git a/core/java/android/nfc/NdefRecord.java b/nfc/java/android/nfc/NdefRecord.java
similarity index 100%
rename from core/java/android/nfc/NdefRecord.java
rename to nfc/java/android/nfc/NdefRecord.java
diff --git a/core/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java
similarity index 100%
rename from core/java/android/nfc/NfcActivityManager.java
rename to nfc/java/android/nfc/NfcActivityManager.java
diff --git a/core/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
similarity index 99%
rename from core/java/android/nfc/NfcAdapter.java
rename to nfc/java/android/nfc/NfcAdapter.java
index 5a40e42..8219d2f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -1802,7 +1802,7 @@
* Use {@link #FLAG_LISTEN_DISABLE} to disable listening.
* Also refer to {@link #resetDiscoveryTechnology(Activity)} to restore these changes.
* </p>
- * The pollTech, listenTech parameters can be one or several of below list.
+ * The pollTechnology, listenTechnology parameters can be one or several of below list.
* <pre>
* Poll Listen
* Passive A 0x01 (NFC_A) 0x01 (NFC_PASSIVE_A)
@@ -1820,25 +1820,25 @@
* NfcAdapter.FLAG_READER_DISABLE, NfcAdapter.FLAG_LISTEN_KEEP);
* }</pre></p>
* @param activity The Activity that requests NFC controller to enable specific technologies.
- * @param pollTech Flags indicating poll technologies.
- * @param listenTech Flags indicating listen technologies.
+ * @param pollTechnology Flags indicating poll technologies.
+ * @param listenTechnology Flags indicating listen technologies.
* @throws UnsupportedOperationException if FEATURE_NFC,
* FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF are unavailable.
*/
@FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
public void setDiscoveryTechnology(@NonNull Activity activity,
- @PollTechnology int pollTech, @ListenTechnology int listenTech) {
- if (listenTech == FLAG_LISTEN_DISABLE) {
+ @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology) {
+ if (listenTechnology == FLAG_LISTEN_DISABLE) {
synchronized (sLock) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
}
- mNfcActivityManager.enableReaderMode(activity, null, pollTech, null);
+ mNfcActivityManager.enableReaderMode(activity, null, pollTechnology, null);
return;
}
- if (pollTech == FLAG_READER_DISABLE) {
+ if (pollTechnology == FLAG_READER_DISABLE) {
synchronized (sLock) {
if (!sHasCeFeature) {
throw new UnsupportedOperationException();
@@ -1851,7 +1851,7 @@
}
}
}
- mNfcActivityManager.setDiscoveryTech(activity, pollTech, listenTech);
+ mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
}
/**
diff --git a/core/java/android/nfc/NfcAntennaInfo.aidl b/nfc/java/android/nfc/NfcAntennaInfo.aidl
similarity index 100%
rename from core/java/android/nfc/NfcAntennaInfo.aidl
rename to nfc/java/android/nfc/NfcAntennaInfo.aidl
diff --git a/core/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java
similarity index 100%
rename from core/java/android/nfc/NfcAntennaInfo.java
rename to nfc/java/android/nfc/NfcAntennaInfo.java
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
similarity index 100%
rename from core/java/android/nfc/NfcControllerAlwaysOnListener.java
rename to nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
diff --git a/core/java/android/nfc/NfcEvent.java b/nfc/java/android/nfc/NfcEvent.java
similarity index 100%
rename from core/java/android/nfc/NfcEvent.java
rename to nfc/java/android/nfc/NfcEvent.java
diff --git a/core/java/android/nfc/NfcFrameworkInitializer.java b/nfc/java/android/nfc/NfcFrameworkInitializer.java
similarity index 100%
rename from core/java/android/nfc/NfcFrameworkInitializer.java
rename to nfc/java/android/nfc/NfcFrameworkInitializer.java
diff --git a/core/java/android/nfc/NfcManager.java b/nfc/java/android/nfc/NfcManager.java
similarity index 100%
rename from core/java/android/nfc/NfcManager.java
rename to nfc/java/android/nfc/NfcManager.java
diff --git a/core/java/android/nfc/NfcServiceManager.java b/nfc/java/android/nfc/NfcServiceManager.java
similarity index 100%
rename from core/java/android/nfc/NfcServiceManager.java
rename to nfc/java/android/nfc/NfcServiceManager.java
diff --git a/core/java/android/nfc/NfcWlcStateListener.java b/nfc/java/android/nfc/NfcWlcStateListener.java
similarity index 100%
rename from core/java/android/nfc/NfcWlcStateListener.java
rename to nfc/java/android/nfc/NfcWlcStateListener.java
diff --git a/core/java/android/nfc/Tag.aidl b/nfc/java/android/nfc/Tag.aidl
similarity index 100%
rename from core/java/android/nfc/Tag.aidl
rename to nfc/java/android/nfc/Tag.aidl
diff --git a/core/java/android/nfc/Tag.java b/nfc/java/android/nfc/Tag.java
similarity index 100%
rename from core/java/android/nfc/Tag.java
rename to nfc/java/android/nfc/Tag.java
diff --git a/core/java/android/nfc/TagLostException.java b/nfc/java/android/nfc/TagLostException.java
similarity index 100%
rename from core/java/android/nfc/TagLostException.java
rename to nfc/java/android/nfc/TagLostException.java
diff --git a/core/java/android/nfc/TechListParcel.aidl b/nfc/java/android/nfc/TechListParcel.aidl
similarity index 100%
rename from core/java/android/nfc/TechListParcel.aidl
rename to nfc/java/android/nfc/TechListParcel.aidl
diff --git a/core/java/android/nfc/TechListParcel.java b/nfc/java/android/nfc/TechListParcel.java
similarity index 100%
rename from core/java/android/nfc/TechListParcel.java
rename to nfc/java/android/nfc/TechListParcel.java
diff --git a/core/java/android/nfc/TransceiveResult.aidl b/nfc/java/android/nfc/TransceiveResult.aidl
similarity index 100%
rename from core/java/android/nfc/TransceiveResult.aidl
rename to nfc/java/android/nfc/TransceiveResult.aidl
diff --git a/core/java/android/nfc/TransceiveResult.java b/nfc/java/android/nfc/TransceiveResult.java
similarity index 100%
rename from core/java/android/nfc/TransceiveResult.java
rename to nfc/java/android/nfc/TransceiveResult.java
diff --git a/core/java/android/nfc/WlcLDeviceInfo.aidl b/nfc/java/android/nfc/WlcLDeviceInfo.aidl
similarity index 100%
rename from core/java/android/nfc/WlcLDeviceInfo.aidl
rename to nfc/java/android/nfc/WlcLDeviceInfo.aidl
diff --git a/core/java/android/nfc/WlcLDeviceInfo.java b/nfc/java/android/nfc/WlcLDeviceInfo.java
similarity index 100%
rename from core/java/android/nfc/WlcLDeviceInfo.java
rename to nfc/java/android/nfc/WlcLDeviceInfo.java
diff --git a/core/java/android/nfc/cardemulation/AidGroup.aidl b/nfc/java/android/nfc/cardemulation/AidGroup.aidl
similarity index 100%
rename from core/java/android/nfc/cardemulation/AidGroup.aidl
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/AidGroup.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/ApduServiceInfo.aidl
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/ApduServiceInfo.java
rename to 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
similarity index 96%
rename from core/java/android/nfc/cardemulation/CardEmulation.java
rename to nfc/java/android/nfc/cardemulation/CardEmulation.java
index ad86d70..81eab71 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -69,7 +69,12 @@
* 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 @@
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
similarity index 100%
rename from core/java/android/nfc/cardemulation/HostApduService.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/HostNfcFService.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/NfcFCardEmulation.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/NfcFServiceInfo.java
rename to nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java
diff --git a/core/java/android/nfc/cardemulation/OWNERS b/nfc/java/android/nfc/cardemulation/OWNERS
similarity index 100%
rename from core/java/android/nfc/cardemulation/OWNERS
rename to nfc/java/android/nfc/cardemulation/OWNERS
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/nfc/java/android/nfc/cardemulation/OffHostApduService.java
similarity index 100%
rename from core/java/android/nfc/cardemulation/OffHostApduService.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/cardemulation/Utils.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/dta/NfcDta.java
rename to nfc/java/android/nfc/dta/NfcDta.java
diff --git a/core/java/android/nfc/dta/OWNERS b/nfc/java/android/nfc/dta/OWNERS
similarity index 100%
rename from core/java/android/nfc/dta/OWNERS
rename to nfc/java/android/nfc/dta/OWNERS
diff --git a/core/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
similarity index 100%
rename from core/java/android/nfc/flags.aconfig
rename to nfc/java/android/nfc/flags.aconfig
diff --git a/core/java/android/nfc/package.html b/nfc/java/android/nfc/package.html
similarity index 100%
rename from core/java/android/nfc/package.html
rename to nfc/java/android/nfc/package.html
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/nfc/java/android/nfc/tech/BasicTagTechnology.java
similarity index 100%
rename from core/java/android/nfc/tech/BasicTagTechnology.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/IsoDep.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/MifareClassic.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/MifareUltralight.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/Ndef.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NdefFormatable.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NfcA.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NfcB.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NfcBarcode.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NfcF.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/NfcV.java
rename to nfc/java/android/nfc/tech/NfcV.java
diff --git a/core/java/android/nfc/tech/OWNERS b/nfc/java/android/nfc/tech/OWNERS
similarity index 100%
rename from core/java/android/nfc/tech/OWNERS
rename to nfc/java/android/nfc/tech/OWNERS
diff --git a/core/java/android/nfc/tech/TagTechnology.java b/nfc/java/android/nfc/tech/TagTechnology.java
similarity index 100%
rename from core/java/android/nfc/tech/TagTechnology.java
rename to 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
similarity index 100%
rename from core/java/android/nfc/tech/package.html
rename to nfc/java/android/nfc/tech/package.html
diff --git a/core/tests/nfctests/Android.bp b/nfc/tests/Android.bp
similarity index 97%
rename from core/tests/nfctests/Android.bp
rename to nfc/tests/Android.bp
index f81be49..62566ee 100644
--- a/core/tests/nfctests/Android.bp
+++ b/nfc/tests/Android.bp
@@ -30,6 +30,7 @@
"truth",
],
libs: [
+ "framework-nfc.impl",
"android.test.runner",
],
srcs: ["src/**/*.java"],
diff --git a/core/tests/nfctests/AndroidManifest.xml b/nfc/tests/AndroidManifest.xml
similarity index 100%
rename from core/tests/nfctests/AndroidManifest.xml
rename to nfc/tests/AndroidManifest.xml
diff --git a/core/tests/nfctests/AndroidTest.xml b/nfc/tests/AndroidTest.xml
similarity index 100%
rename from core/tests/nfctests/AndroidTest.xml
rename to nfc/tests/AndroidTest.xml
diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
similarity index 100%
rename from core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
rename to 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
similarity index 100%
rename from core/tests/nfctests/src/android/nfc/TechListParcelTest.java
rename to nfc/tests/src/android/nfc/TechListParcelTest.java
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 2f0c83b..5becc86 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 e4e9f7a..0000000
--- 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 0000000..cb6c6b4
--- /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 63b9f24..dcb7ef9 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 67003a3..2a4719d 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 4a5761a..7de941e 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 8ac364e7..58467af 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.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
@@ -69,7 +70,8 @@
companion object {
private const val TAG = "CredAutofill"
- private const val SESSION_ID_KEY = "session_id"
+ private const val SESSION_ID_KEY = "autofill_session_id"
+ private const val REQUEST_ID_KEY = "autofill_request_id"
private const val CRED_HINT_PREFIX = "credential="
private const val REQUEST_DATA_KEY = "requestData"
private const val CANDIDATE_DATA_KEY = "candidateQueryData"
@@ -97,16 +99,23 @@
val callingPackage = structure.activityComponent.packageName
Log.i(TAG, "onFillCredentialRequest called for $callingPackage")
- var sessionId = request.clientState?.getInt(SESSION_ID_KEY)
-
- Log.i(TAG, "Autofill sessionId: " + sessionId)
- if (sessionId == null) {
- Log.i(TAG, "Session Id not found")
- callback.onFailure("Session Id not found")
+ val clientState = request.clientState
+ if (clientState == null) {
+ Log.i(TAG, "Client state not found")
+ callback.onFailure("Client state not found")
+ return
+ }
+ val sessionId = clientState.getInt(SESSION_ID_KEY)
+ val requestId = clientState.getInt(REQUEST_ID_KEY)
+ Log.i(TAG, "Autofill sessionId: $sessionId, autofill requestId: $requestId")
+ if (sessionId == 0 || requestId == 0) {
+ Log.i(TAG, "Session Id or request Id not found")
+ callback.onFailure("Session Id or request Id not found")
return
}
- val getCredRequest: GetCredentialRequest? = getCredManRequest(structure)
+ val getCredRequest: GetCredentialRequest? = getCredManRequest(structure, sessionId,
+ requestId)
if (getCredRequest == null) {
Log.i(TAG, "No credential manager request found")
callback.onFailure("No credential manager request found")
@@ -305,12 +314,14 @@
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@{
@@ -347,12 +358,19 @@
} 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(
@@ -515,12 +533,19 @@
TODO("Not yet implemented")
}
- private fun getCredManRequest(structure: AssistStructure): GetCredentialRequest? {
+ private fun getCredManRequest(
+ structure: AssistStructure,
+ sessionId: Int,
+ requestId: Int
+ ): GetCredentialRequest? {
val credentialOptions: MutableList<CredentialOption> = mutableListOf()
traverseStructure(structure, credentialOptions)
if (credentialOptions.isNotEmpty()) {
- return GetCredentialRequest.Builder(Bundle.EMPTY)
+ val dataBundle = Bundle()
+ dataBundle.putInt(SESSION_ID_KEY, sessionId)
+ dataBundle.putInt(REQUEST_ID_KEY, requestId)
+ return GetCredentialRequest.Builder(dataBundle)
.setCredentialOptions(credentialOptions)
.build()
}
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 4dc7f00..e039dea 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.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 @@
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 @@
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 3d0b945..b1e5d75 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/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
index 170cb45..9ad3e3c 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java
@@ -91,7 +91,8 @@
// be stale, if e.g. the app was uninstalled while the activity was destroyed.
super.onCreate(null);
- if (usePiaV2() && !isTv()) {
+ // TODO(b/318521110) Enable PIA v2 for archive dialog.
+ if (usePiaV2() && !isTv() && !isArchiveDialog(getIntent())) {
Log.i(TAG, "Using Pia V2");
boolean returnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
@@ -224,6 +225,11 @@
showConfirmationDialog();
}
+ private boolean isArchiveDialog(Intent intent) {
+ return (intent.getIntExtra(PackageInstaller.EXTRA_DELETE_FLAGS, 0)
+ & PackageManager.DELETE_ARCHIVE) != 0;
+ }
+
/**
* Parses specific {@link android.content.pm.PackageManager.DeleteFlags} from {@link Intent}
* to archive an app if requested.
diff --git a/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml b/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml
index 7f16517..8127e1a 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 ffe3d1d..5da4b95 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -61,7 +61,7 @@
"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 e9c687f..13bf5f5 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 d9f74da..010a6ce 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -28,7 +28,4 @@
"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 cfa64a4..0000000
--- 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 26d05a6..45a07fe 100644
--- a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
@@ -1,38 +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">
-
- <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=" ~~">
- <location
- file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="97"
- column="56"/>
- </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=" ~~">
- <location
- file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="140"
- column="57"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 26 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`"
- errorLine1=" adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="75"
- column="34"/>
- </issue>
+<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"
@@ -58,6 +25,28 @@
<issue
id="NewApi"
+ message="Call requires API level 26 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`"
+ errorLine1=" adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
+ line="75"
+ column="34"/>
+ </issue>
+
+ <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=" ~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
+ line="97"
+ column="56"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~">
@@ -67,4 +56,15 @@
column="17"/>
</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=" ~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
+ 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 0744710..db6a882 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 53346e0..3cfca1d 100644
--- a/packages/SettingsLib/SearchProvider/lint-baseline.xml
+++ b/packages/SettingsLib/SearchProvider/lint-baseline.xml
@@ -1,27 +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">
-
- <issue
- id="NewApi"
- 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="107"
- column="13"/>
- </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=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="97"
- column="69"/>
- </issue>
+<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"
@@ -36,6 +14,39 @@
<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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
+ line="45"
+ column="54"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
+ 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>
+
+ <issue
+ id="NewApi"
message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#className`"
errorLine1=" .add(XmlResource.COLUMN_CLASS_NAME, indexableResource.className)"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -58,6 +69,39 @@
<issue
id="NewApi"
+ 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="56"
+ column="29"/>
+ </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=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
+ line="97"
+ column="69"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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="107"
+ column="13"/>
+ </issue>
+
+ <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=" ~~~~~~~~~~~~~~~~~">
@@ -81,17 +125,6 @@
<issue
id="NewApi"
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="56"
- column="29"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`"
errorLine1=" this.intentTargetClass = className;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
@@ -100,37 +133,4 @@
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=" ~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- 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>
-
- <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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="45"
- column="54"/>
- </issue>
-
</issues>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 0e40db2..f44b161 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -14,11 +14,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary</item>
<item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
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 a9974dc..514ad669 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.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 @@
) {
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 326ec0d..56b1bca 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 3fcd56c..2f6cc3a 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=" ~~">
+ 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="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=" ~~">
- <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,35 +25,13 @@
<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"/>
- </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=" ~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java"
- line="62"
- column="60"/>
- </issue>
-
- <issue
- id="NewApi"
- 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="163"
- column="37"/>
+ line="80"
+ column="29"/>
</issue>
<issue
@@ -80,13 +47,13 @@
<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=" mContext.getPackageName(), 0, UserHandle.of(managedUserId)"
+ errorLine2=" ~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="80"
- column="29"/>
+ line="119"
+ column="70"/>
</issue>
<issue
@@ -102,6 +69,28 @@
<issue
id="NewApi"
+ 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="150"
+ column="47"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ 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="163"
+ column="37"/>
+ </issue>
+
+ <issue
+ id="NewApi"
message="Call requires API level 30 (current min is 21): `android.os.UserManager#getAllProfiles`"
errorLine1=" List<UserHandle> allProfiles = mUserManager.getAllProfiles();"
errorLine2=" ~~~~~~~~~~~~~~">
@@ -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 d6a23fd..0000000
--- 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 640d4e9..071258d 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 3b14712..390c9d2e 100644
--- a/packages/SettingsLib/search/Android.bp
+++ b/packages/SettingsLib/search/Android.bp
@@ -12,9 +12,6 @@
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 7ec512b..61cdb05 100644
--- a/packages/SettingsLib/search/lint-baseline.xml
+++ b/packages/SettingsLib/search/lint-baseline.xml
@@ -1,16 +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">
-
- <issue
- id="NewApi"
- 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="62"
- column="9"/>
- </issue>
+<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"
@@ -23,4 +12,15 @@
column="41"/>
</issue>
+ <issue
+ id="NewApi"
+ 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="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 8e5396f..d902457 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -19,6 +19,7 @@
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.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 @@
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 @@
}
/**
- * 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 5bc27195..943e3fc 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 @@
@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 @@
@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 24fd06e..e7487e8 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 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 @@
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 @@
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 @@
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 1481d97..16de478 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -231,6 +231,7 @@
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 @@
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 d3a89f4..d61ae7e 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -438,6 +438,7 @@
"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 21263a9..f7b1a26 100644
--- a/packages/SystemUI/aconfig/accessibility.aconfig
+++ b/packages/SystemUI/aconfig/accessibility.aconfig
@@ -10,6 +10,13 @@
}
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 @@
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 5b21854..c23a49c 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -208,6 +208,13 @@
}
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 {
+ 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 fd04b5ee0..f4ffb3c 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.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 @@
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 d31547b..43745f9 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.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 @@
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 1860c9f..2b1268e 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 6591543..d949396 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.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 @@
}
}
-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 d638ffe..428bc39 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.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 249b3e1..b704864 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.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 @@
* 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 @@
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 @@
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 d201544..d76f0ff 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.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,10 +77,12 @@
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
@@ -97,6 +100,8 @@
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 +138,10 @@
}
}
+ 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.
@@ -172,7 +181,7 @@
gridModifier =
gridModifier
.fillMaxSize()
- .dragContainer(dragDropState, beforeContentPadding(contentPadding))
+ .dragContainer(dragDropState, beforeContentPadding(contentPadding), viewModel)
.onGloballyPositioned { setGridCoordinates(it) }
// for widgets dropped from other activities
val dragAndDropTargetState =
@@ -319,8 +328,40 @@
}
@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),
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 1b40de4..1138221 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -40,6 +40,7 @@
import androidx.compose.ui.unit.toSize
import androidx.compose.ui.zIndex
import com.android.systemui.communal.ui.compose.extensions.plus
+import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
@@ -207,7 +208,8 @@
fun Modifier.dragContainer(
dragDropState: GridDragDropState,
- beforeContentPadding: ContentPaddingInPx
+ beforeContentPadding: ContentPaddingInPx,
+ viewModel: BaseCommunalViewModel,
): Modifier {
return pointerInput(dragDropState, beforeContentPadding) {
detectDragGesturesAfterLongPress(
@@ -220,9 +222,16 @@
offset,
Offset(beforeContentPadding.startPadding, beforeContentPadding.topPadding)
)
+ viewModel.onReorderWidgetStart()
},
- onDragEnd = { dragDropState.onDragInterrupted() },
- onDragCancel = { dragDropState.onDragInterrupted() }
+ onDragEnd = {
+ dragDropState.onDragInterrupted()
+ viewModel.onReorderWidgetEnd()
+ },
+ onDragCancel = {
+ dragDropState.onDragInterrupted()
+ viewModel.onReorderWidgetCancel()
+ }
)
}
}
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 0eec024..0b26ae9 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.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 @@
val ShelfSpace = ElementKey("ShelfSpace")
}
- object SharedValues {
- val SharedExpansionValue = ValueKey("SharedExpansionValue")
- }
-
enum class Form {
HunFromTop,
Stack,
@@ -181,13 +174,6 @@
)
}
) {
- 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 4eb9089..c35202c 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.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.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 @@
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 @@
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 ba6d00e..7d3b0fb 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 @@
* 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 @@
// 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 @@
// 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 @@
}
// 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 280fbfb..a910bca 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.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 @@
/** 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 @@
companion object {
val SizeUnspecified = IntSize(Int.MAX_VALUE, Int.MAX_VALUE)
- val AlphaUnspecified = Float.MIN_VALUE
}
}
@@ -219,7 +195,7 @@
}
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 @@
// 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 @@
}
private fun isSharedElementEnabled(
- layoutState: SceneTransitionLayoutStateImpl,
+ layoutState: BaseSceneTransitionLayoutState,
transition: TransitionState.Transition,
element: ElementKey,
): Boolean {
@@ -312,7 +287,7 @@
}
internal fun sharedElementTransformation(
- layoutState: SceneTransitionLayoutStateImpl,
+ layoutState: BaseSceneTransitionLayoutState,
transition: TransitionState.Transition,
element: ElementKey,
): SharedElementTransformation? {
@@ -342,18 +317,9 @@
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 @@
layoutImpl: SceneTransitionLayoutImpl,
element: Element,
scene: Scene,
- sceneState: Element.SceneState,
): Float {
return computeValue(
layoutImpl,
@@ -393,10 +358,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
// 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 @@
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 af3c099..cdc4778 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 @@
// 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 454c0ec..b346a70 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
- }
-
- val element = layoutImpl.elements.getValue(element)
- drawIntoCanvas { canvas ->
- canvas.withSaveLayer(size.toRect(), Paint()) {
- drawContent()
-
- val offset = bounds.lastSharedState.offset - element.lastSharedState.offset
- translate(offset.x, offset.y) { drawHole(bounds) }
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ return measurable.measure(constraints).run {
+ layout(width, height) {
+ placeWithLayer(0, 0) { compositingStrategy = CompositingStrategy.Offscreen }
}
}
}
- private fun DrawScope.drawHole(bounds: Element) {
- val boundsSize = bounds.lastSharedState.size.toSize()
+ override fun ContentDrawScope.draw() {
+ drawContent()
+
+ val holeSize = size()
+ if (holeSize != Size.Zero) {
+ val offset = offset()
+ translate(offset.x, offset.y) { drawHole(holeSize) }
+ }
+ }
+
+ 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 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 3537b79..f67df54 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.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 @@
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 338557d..64388b7 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 @@
// 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 @@
}
}
- 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 @@
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 @@
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 84fade89..80f8c1c 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 @@
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 @@
* 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 @@
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 @@
): 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 @@
*/
@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 @@
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 @@
// SnapshotStateMap anymore.
layoutImpl.updateScenes(scenes)
- val targetSceneChannel = remember { Channel<SceneKey>(Channel.CONFLATED) }
SideEffect {
if (state != layoutImpl.state) {
error(
@@ -384,23 +393,8 @@
)
}
- 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 0227aba..7cc9d26 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.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 @@
@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 @@
?: 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 @@
// 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 0607aa1..956e326 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 @@
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 @@
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 @@
}
}
-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 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 @@
}
}
}
+
+/**
+ * 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 35a5054..c0de87a 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.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 @@
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 @@
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 @@
scrollScope = rememberCoroutineScope()
SceneTransitionLayoutForTesting(
- currentScene = TestScenes.SceneA,
- onChangeScene = {},
+ state =
+ updateSceneTransitionLayoutState(
+ currentScene = TestScenes.SceneA,
+ onChangeScene = {}
+ ),
onLayoutImpl = { nullableLayoutImpl = it },
) {
scene(TestScenes.SceneA) {
@@ -565,86 +567,4 @@
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 04b3f8a..0f9b024 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 @@
@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 @@
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 d9ce519..066a3e4 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 @@
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 @@
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 @@
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 75dee47..48825fb 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 @@
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 @@
@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 @@
@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 @@
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 649e499..efaea71 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 @@
}
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 @@
/** 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 58d853e..1ec3c8b 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.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 @@
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 @@
// 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 @@
// 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 @@
@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 @@
@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 cb122dc..fbcd5b2 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 @@
*
* 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 41bde52..3dfe65a 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.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 @@
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 c8461d2..02d30c5e 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 @@
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 cbcca55..f775175 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 @@
mSelectedUserInteractor
)
underTest.init()
+ underTest.onViewAttached()
underTest.onResume(0)
verify(keyguardUpdateMonitor)
.registerCallback(updateMonitorCallbackArgumentCaptor.capture())
+ reset(keyguardMessageAreaController)
+ reset(keyguardUpdateMonitor)
}
@Test
@@ -110,25 +113,24 @@
underTest.onViewAttached()
verify(keyguardMessageAreaController)
.setMessage(context.resources.getString(R.string.keyguard_enter_your_pin), false)
- }
-
- @Test
- fun onViewDetached() {
- underTest.onViewDetached()
- }
-
- @Test
- fun onResume() {
- reset(keyguardUpdateMonitor)
- underTest.onResume(KeyguardSecurityView.VIEW_REVEALED)
verify(keyguardUpdateMonitor)
.registerCallback(any(KeyguardUpdateMonitorCallback::class.java))
}
@Test
+ fun onViewDetached() {
+ underTest.onViewDetached()
+ verify(keyguardUpdateMonitor).removeCallback(any(KeyguardUpdateMonitorCallback::class.java))
+ }
+
+ @Test
+ fun onResume() {
+ underTest.onResume(KeyguardSecurityView.VIEW_REVEALED)
+ }
+
+ @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 74f50d8..27d1eb7 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 @@
@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 @@
settings.putIntForUser(
ColorCorrectionRepositoryImpl.SETTING_NAME,
1,
- TEST_USER_1.identifier
+ testUser1.identifier
)
underTest =
@@ -72,84 +70,84 @@
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 @@
@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 3f05fef..423e124 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 @@
@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 @@
@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 @@
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 @@
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 1c1335f..343280d 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 @@
}
@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 15633d1..4a39799 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 @@
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 @@
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 @@
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 cec2d74..a59a4b8 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 @@
}
@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 0000000..ccf119a
--- /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
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/PrimaryBouncerInteractorTest.kt
index ee46f76..63f6c20 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 @@
@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 744b65f..cd83c07 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.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.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 @@
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 @@
}
@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 0000000..721fc49
--- /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 c638e1e..54510a8 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,11 +21,11 @@
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
import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.FakeCommunalRepository
@@ -33,19 +33,18 @@
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory
import com.android.systemui.communal.domain.model.CommunalContentModel
+import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
import com.android.systemui.communal.ui.viewmodel.CommunalEditModeViewModel
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
@@ -54,6 +53,7 @@
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)
@@ -61,9 +61,8 @@
@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
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
@@ -93,9 +92,8 @@
CommunalEditModeViewModel(
withDeps.communalInteractor,
appWidgetHost,
- Provider { shadeViewController },
- powerManager,
mediaHost,
+ uiEventLogger,
)
}
@@ -203,4 +201,22 @@
val providerTwo = ComponentName("pkg.test", "testWidget2")
underTest.onAddWidget(componentName = providerTwo, priority = 0)
}
+
+ @Test
+ fun reorderWidget_uiEventLogging_start() {
+ underTest.onReorderWidgetStart()
+ verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
+ }
+
+ @Test
+ fun reorderWidget_uiEventLogging_end() {
+ underTest.onReorderWidgetEnd()
+ verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_FINISH)
+ }
+
+ @Test
+ fun reorderWidget_uiEventLogging_cancel() {
+ underTest.onReorderWidgetCancel()
+ verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
+ }
}
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 16e0bc0..a776062 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,17 +30,18 @@
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.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
@@ -50,12 +50,11 @@
import org.mockito.Mockito
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,11 +83,10 @@
underTest =
CommunalViewModel(
+ testScope,
withDeps.communalInteractor,
WidgetInteractionHandler(mock()),
withDeps.tutorialInteractor,
- Provider { shadeViewController },
- powerManager,
mediaHost,
)
}
@@ -159,4 +157,44 @@
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 3d1efa5..5827671 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 @@
}
/**
- * 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 @@
reset(mScrimController);
- // Scroll gesture is not consumed.
+ // Scroll gesture is 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 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))
+ .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 b483085..9bccf4e2 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 @@
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 e7037a6..9daf186 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 @@
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 0000000..c7ab529
--- /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 e141c2b..f1690daf 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 @@
testScope,
)
- assertThat(values.size).isEqualTo(6)
+ assertThat(values.size).isEqualTo(7)
values.forEach { assertThat(it).isIn(Range.closed(0f, 100f)) }
}
@@ -117,7 +117,7 @@
testScope,
)
- assertThat(values.size).isEqualTo(3)
+ assertThat(values.size).isEqualTo(4)
values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
}
@@ -232,7 +232,7 @@
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 897ce6d..f763a67 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 @@
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 @@
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 5b88ebe6..fd2fd2f 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 @@
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 4843f8b..74025fd 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 @@
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 @@
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 a1b8aab..6fcb0c1 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 @@
),
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 2111ad5..639114c 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.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 @@
fun lockscreenFadeIn() =
testScope.runTest {
val values by collectValues(underTest.lockscreenAlpha)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
listOf(
@@ -83,6 +85,7 @@
100
)
val values by collectValues(underTest.lockscreenTranslationY)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
listOf(
@@ -95,7 +98,7 @@
testScope,
)
- assertThat(values.size).isEqualTo(4)
+ assertThat(values.size).isEqualTo(5)
values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
}
@@ -107,6 +110,7 @@
100
)
val values by collectValues(underTest.lockscreenTranslationY)
+ runCurrent()
keyguardTransitionRepository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
@@ -117,6 +121,7 @@
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 90b8362..30b87bb 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.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 @@
fun bouncerAlpha() =
testScope.runTest {
val values by collectValues(underTest.bouncerAlpha)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
listOf(
@@ -83,6 +85,7 @@
fun bouncerAlpha_runDimissFromKeyguard() =
testScope.runTest {
val values by collectValues(underTest.bouncerAlpha)
+ runCurrent()
whenever(primaryBouncerInteractor.willRunDismissFromKeyguard()).thenReturn(true)
@@ -95,7 +98,7 @@
testScope,
)
- assertThat(values.size).isEqualTo(1)
+ assertThat(values.size).isEqualTo(2)
values.forEach { assertThat(it).isEqualTo(0f) }
}
@@ -103,11 +106,12 @@
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 @@
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 @@
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 bd1c310..c104977 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 @@
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 e44c849..be2da17 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 @@
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 @@
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
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerMainThreadTest.java
index 01fe40f..d0e05fa 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.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.concurrent.Executor;
@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@RunWith(AndroidJUnit4.class)
public class NotificationLockscreenUserManagerMainThreadTest extends SysuiTestCase {
@Mock
private NotificationPresenter mPresenter;
@@ -128,6 +123,7 @@
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 @@
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 @@
// 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 @@
(() -> 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
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 757f16c..bcc0710 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.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.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.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 @@
@SmallTest
@RunWith(ParameterizedAndroidJunit4.class)
-@TestableLooper.RunWithLooper
public class NotificationLockscreenUserManagerTest extends SysuiTestCase {
@Parameters(name = "{0}")
@@ -197,8 +196,6 @@
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 @@
(() -> 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 0000000..8a0400d
--- /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 0000000..12469dd
--- /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 0000000..ebc81be
--- /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 0000000..26c0f80
--- /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 3e5e8a0..f0ce460 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 @@
import android.content.ComponentName;
+import java.util.function.BiConsumer;
+
/**
* Provides the ability for consumers to control plugin lifecycle.
*
@@ -33,11 +35,8 @@
/** 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 18d63ab..01b99ec 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/color/notification_state_color_dark.xml b/packages/SystemUI/res/color/notification_state_color_dark.xml
new file mode 100644
index 0000000..d26cbd5
--- /dev/null
+++ b/packages/SystemUI/res/color/notification_state_color_dark.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <!-- Pressed state's alpha is set to 0.00 temporarily until this bug is resolved permanently
+ b/313920497 Design intended alpha is 0.15-->
+ <item android:state_pressed="true" android:color="#ffffff" android:alpha="0.00" />
+ <item android:state_hovered="true" android:color="#ffffff" android:alpha="0.11" />
+ <item android:color="@color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/notification_overlay_color.xml b/packages/SystemUI/res/color/notification_state_color_default.xml
similarity index 100%
rename from packages/SystemUI/res/color/notification_overlay_color.xml
rename to packages/SystemUI/res/color/notification_state_color_default.xml
diff --git a/packages/SystemUI/res/color/notification_state_color_light.xml b/packages/SystemUI/res/color/notification_state_color_light.xml
new file mode 100644
index 0000000..3e8bcf3
--- /dev/null
+++ b/packages/SystemUI/res/color/notification_state_color_light.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <!-- Pressed state's alpha is set to 0.00 temporarily until this bug is resolved permanently
+ b/313920497 Design intended alpha is 0.15-->
+ <item android:state_pressed="true" android:color="#000000" android:alpha="0.00" />
+ <item android:state_hovered="true" android:color="#000000" android:alpha="0.11" />
+ <item android:color="@color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 355e75d..3f903ae 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -25,7 +25,7 @@
</item>
<item>
<shape>
- <solid android:color="@color/notification_overlay_color" />
+ <solid android:color="@color/notification_state_color_default" />
</shape>
</item>
</layer-list>
\ No newline at end of file
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 0000000..2161a62
--- /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 0000000..2161a62
--- /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 0000000..3908757
--- /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
similarity index 61%
rename from packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
rename to packages/SystemUI/res/layout/biometric_prompt_content_row_item_text_view.xml
index 9d16f32d..e39f60f 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/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml
similarity index 61%
copy from packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
copy to packages/SystemUI/res/layout/biometric_prompt_content_row_layout.xml
index 9d16f32d..6c86736 100644
--- a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
+++ b/packages/SystemUI/res/layout/biometric_prompt_content_row_layout.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
+<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 bea0e13..23fbb12 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 6d7ce06..e602d6c 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 fc0bf24..4cb7591 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 83c8a51..0000000
--- 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 db4cca3..aeb8311 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 40fddc8..8bad367 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 d19c77b..2566df7 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 4e78f55..591c125 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 bf32c5e..978c295 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 56c3e45..1668de0 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 3bc6269..8d2adda 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 22d167e..6f5890f 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 045af93..601b29a 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 ae962ce..287eed7 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 8cf8828..d56e4f0 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 17084dc..9c71436 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 41abea3..06f9ff3 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 d95e229..2acd2fe 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 5848e4f..79d350b 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 870e4dd..afd2e72 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 f25baf2..a0000ef 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 870e4dd..afd2e72 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 870e4dd..afd2e72 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 b3ed714..835cf38 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 c535560..a12c574 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 1157ff1..765f2e3 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 36b3f1e..249e45f 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 5ea02d1..1a0d482 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 aa77b4b..b77c949 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 882c42c..b764e07 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 8370b01..68f69a6 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 af81a31..0c8ef28 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 ef0751b..a705f2ae 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 d92231c..9965f45 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 f8c78a9..e2ed3ab 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 0803aeb..f5d73ea 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 fd9d832..9ac44df 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 a9252e2..0d59017 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 8ef809a..a0b5199 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 cef3285..3a0843e 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 c5079fe..8ee96fc 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 486b22f..17236ea 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 c742f93..e193cb1 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 9d386ef..c841d1c 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 d2c60f1..f81ad05 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 ec81523..09b9e15 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 33f4528..e217154 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 876562d..250eb5a 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 897b266..940b66d 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 2f091ec..a6234c3 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 c0c5d44..87ca722 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 83d2724..eee0f7d 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 4bc71c3..8631d20 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 28a2a02..8f7c269 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 057f0b0..6f8ebc9 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 933652b..cb0eff5 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 aad269b..1a19c6b 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 8287d2b..3bdb184 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 25afad4..af2d583 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 d915743..89f58d7 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 4abb4a4..51d5044 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 0576730..9055195 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 cb58e64..9a31fc0 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 0340bd1..bd71d5f 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 aa24818..c569f62 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 c65c56e..001872a 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 0b9580d..44317ae 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 c65c56e..001872a 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 b2fdef3..ab31599 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 ff4bd45..b6ff0db 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 4b4d08b..5c9faab 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 9e9507e..ae567c7 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 cba5416..c2f2693 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 b35668f..4443954 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 1d45fbd..ac1d7bf 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 0d6272f..f8dbbc5 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 1bd2ed7..dbc2eea 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 0cd076f..d70992e 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 6a59812..c87762e 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 dc4c6cf..ab50427 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 c09ac97..dcd687a 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 ee1909b..f043404 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 04a97bc..fce90e5 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 fd984b9..1ae2118 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 b9a9832..67d3db8 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 b1ff9a8..e4ae7be 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 237fd57..7fd84d9 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 313af30..568f823 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 6a13d3d..86e6535 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 23862a7..564ba33 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 5f6a39a..8be1cc7 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/config.xml b/packages/SystemUI/res/values/config.xml
index 64a1d24..17719d1 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1002,4 +1002,7 @@
<item>com.android.switchaccess.SwitchAccessService</item>
<item>com.google.android.apps.accessibility.voiceaccess.JustSpeakService</item>
</string-array>
+
+ <!-- Whether to use a machine learning model for back gesture falsing. -->
+ <bool name="config_useBackGestureML">true</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 90d8cdb..798fc06b 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 c925b26..fad4d4f 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 3f11fae..1989589 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 3f026a4..ab3cacb 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>
@@ -921,7 +944,7 @@
<style name="Theme.ControlsActivity" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="android:windowActivityTransitions">true</item>
<item name="android:windowContentTransitions">false</item>
- <item name="android:windowIsTranslucent">false</item>
+ <item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/black</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:statusBarColor">@android:color/black</item>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
deleted file mode 100644
index 7719d5e..0000000
--- 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 05106c9..326c7ef 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -34,9 +34,6 @@
srcs: [
":statslog-SystemUI-java-gen",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
android_library {
@@ -74,9 +71,6 @@
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
kotlincflags: ["-Xjvm-default=all"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -88,9 +82,6 @@
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_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 4bd6729..0000000
--- 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 387f2e1..87cc86f 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 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 @@
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 @@
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 @@
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 @@
/** 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 synchronized void loadPlugin() {
if (mPlugin != null) {
- logDebug("Load request when already loaded");
+ log("Load request when already loaded");
return;
}
@@ -157,7 +154,7 @@
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 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 823bd2d..7088829 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 @@
*/
void onNavButtonsDarkIntensityChanged(float darkIntensity) = 22;
- /**
- * Sent when split keyboard shortcut is triggered to enter stage split.
- */
- void enterStageSplitFromRunningApp(boolean leftOrTop) = 25;
+ /**
+ * Sent when when navigation bar luma sampling is enabled or disabled.
+ */
+ void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) = 23;
- /**
- * Sent when the surface for navigation bar is created or changed
- */
- void onNavigationBarSurface(in SurfaceControl surface) = 26;
+ /**
+ * Sent when split keyboard shortcut is triggered to enter stage split.
+ */
+ void enterStageSplitFromRunningApp(boolean leftOrTop) = 25;
- /**
- * Sent when the task bar stash state is toggled.
- */
- void onTaskbarToggled() = 27;
+ /**
+ * 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 74b975c..de7c12d 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 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 @@
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 e457ca1..8e5d0da 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -1111,7 +1111,7 @@
}
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 c5e7070..5729119 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -105,6 +105,13 @@
@Override
protected void onViewAttached() {
super.onViewAttached();
+ mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+ }
+
+ @Override
+ protected void onViewDetached() {
+ super.onViewDetached();
+ mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
}
@Override
@@ -128,14 +135,12 @@
@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 2a54a4e..d372f5a 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.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 @@
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 @@
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 49e0df6..568b24d 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 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 @@
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 0000000..b5eeaa1
--- /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 62d5feb..6869bba 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.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 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 @@
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 @@
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 @@
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 @@
@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 @@
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;
+ }
- final TextView messageText = (TextView) mMessageView.getChildAt(Index.TEXT_VIEW);
- messageText.setText(getMessageText(newTargetFeatures));
+ // 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));
+ }
});
addView(mMenuView, LayerIndex.MENU_VIEW);
@@ -456,6 +483,50 @@
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 @@
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 093a1ff..a40b4d7 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.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 @@
}
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 @@
}
/**
+ * 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 d664637..81de0a2 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 @@
@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 @@
+ 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 @@
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 @@
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 abbfa01..86802a5b 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 @@
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 @@
}
}
- //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 0000000..e6939f0
--- /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 8fbb250..4377937 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 @@
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 0000000..dddadbd
--- /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 0d72b9c..60b454e 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 @@
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 0000000..22b02da
--- /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 7b8cb82..04dc7a8 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.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 @@
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 @@
}
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 @@
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 1a7b6c9..c3bbaed 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 @@
fun bind(
view: BiometricPromptLayout,
viewModel: PromptViewModel,
- viewsToHideWhenSmall: List<TextView>,
+ viewsToHideWhenSmall: List<View>,
viewsToFadeInOnSizeChange: List<View>,
panelViewController: AuthPanelController,
jankListener: BiometricJankListener,
@@ -110,7 +110,7 @@
// 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 @@
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 @@
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 d899827e..1c78928 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 @@
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 c2a1d8f..d0ff185 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.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 @@
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 @@
@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 654fa22..8c87b0c 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.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 @@
/** 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 @@
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 0000000..02b444f
--- /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/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt
index 7b9634a..5defe475 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/BouncerDialogFactory.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.bouncer.ui
-import com.android.systemui.kosmos.Kosmos
+import android.app.AlertDialog
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+/** 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 7f3b794..f3903de 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 @@
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 0000000..dd253a8
--- /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 0000000..7b05395
--- /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 24d4c6c..9fa4cd6 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 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 @@
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 @@
}
}
}
+
+/** 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 0000000..889023e
--- /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 e167f3e..b64c195 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 @@
/** 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 97e530a..84708a4 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 @@
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) {}
@@ -116,4 +96,13 @@
/** Gets the interaction handler used to handle taps on a remote view */
abstract fun getInteractionHandler(): RemoteViews.InteractionHandler
+
+ /** Called as the user starts dragging a widget to reorder. */
+ open fun onReorderWidgetStart() {}
+
+ /** Called as the user finishes dragging a widget to reorder. */
+ open fun onReorderWidgetEnd() {}
+
+ /** Called as the user cancels dragging a widget to reorder. */
+ open fun onReorderWidgetCancel() {}
}
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 a03e6c1..7faf653 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,18 +23,17 @@
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
import com.android.systemui.communal.domain.model.CommunalContentModel
+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
@@ -47,10 +46,9 @@
constructor(
private val communalInteractor: CommunalInteractor,
private val appWidgetHost: AppWidgetHost,
- shadeViewController: Provider<ShadeViewController>,
- powerManager: PowerManager,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
-) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
+ private val uiEventLogger: UiEventLogger,
+) : BaseCommunalViewModel(communalInteractor, mediaHost) {
private companion object {
private const val KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle"
@@ -135,4 +133,16 @@
pendingConfiguration?.complete(resultCode)
?: throw IllegalStateException("No widget pending configuration")
}
+
+ override fun onReorderWidgetStart() {
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
+ }
+
+ override fun onReorderWidgetEnd() {
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_FINISH)
+ }
+
+ override fun onReorderWidgetCancel() {
+ uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
+ }
}
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 066e897..7a96fab 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,40 @@
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.MediaHost
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 +66,45 @@
}
}
+ private val _isPopupOnDismissCtaShowing: MutableStateFlow<Boolean> = MutableStateFlow(false)
+ override val isPopupOnDismissCtaShowing: Flow<Boolean> =
+ _isPopupOnDismissCtaShowing.asStateFlow()
+
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 bfc6f2b..380ed61 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.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 @@
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 @@
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 @@
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 3a92739..acbdecc 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.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 @@
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 87a736d..8d82b55 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.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 @@
@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 4e4b79c..7f3b5eb 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 @@
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 699532c..846736c 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 @@
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 @@
// 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 @@
// 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 @@
// 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 a34730e..5cebd96 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 @@
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 @@
}
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 cb0f186..42f14f1 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 @@
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 ecf78d5..b1a2297 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 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 @@
*/
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 52f2759..7b1466c 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 @@
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.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 @@
@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 @@
.sample(
combine(
keyguardInteractor.primaryBouncerShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
powerInteractor.isAwake,
keyguardInteractor.isAodAvailable,
::toQuad
@@ -102,20 +109,19 @@
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 @@
}
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 8584401..fedd63b 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 @@
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.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 @@
@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 @@
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Pair
),
@@ -77,7 +84,6 @@
} else {
TransitionModeOnCanceled.LAST_VALUE
}
-
startTransitionTo(
toState = toState,
modeOnCanceled = modeOnCanceled,
@@ -89,16 +95,13 @@
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 @@
}
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 eca7088..fcb7698 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 @@
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.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 @@
@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 @@
powerInteractor.isAwake
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Pair
),
@@ -76,7 +83,7 @@
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 @@
}
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 dac6ef5..a6cdaa8 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 @@
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.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 @@
@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 @@
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -88,7 +95,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardOccluded,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair,
),
::toTriple
@@ -108,7 +115,7 @@
private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isBouncerShowing, lastStartedTransitionStep) ->
if (
isBouncerShowing &&
@@ -123,7 +130,7 @@
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 @@
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 7fdcf2f..13ffd63 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 @@
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.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 @@
@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 @@
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 @@
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 @@
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 @@
}
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 70c2e6d..48b3d9a 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 @@
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 @@
}
}
+ /**
+ * 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 62a0b0e..742790e 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 @@
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.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 @@
@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 @@
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 @@
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 @@
keyguardInteractor.isAbleToDream
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isActiveDreamLockscreenHosted,
::Pair
),
@@ -106,7 +113,7 @@
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 cecc653..8b2b45f 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 @@
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 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 @@
listenForLockscreenToPrimaryBouncerDragging()
listenForLockscreenToAlternateBouncer()
listenForLockscreenTransitionToCamera()
+ listenForLockscreenToGlanceableHub()
}
/**
@@ -147,12 +158,12 @@
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 @@
}
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 @@
}
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 @@
/* 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,64 +236,66 @@
::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 (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
- ) {
- 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 }
+ // 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 (
- keyguardState.to == KeyguardState.LOCKSCREEN &&
- shadeRepository.legacyShadeTracking.value &&
- !isKeyguardUnlocked &&
- statusBarState == KEYGUARD
- ) {
- 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
+ )
+ }
}
}
}
@@ -290,7 +303,7 @@
}
fun dismissKeyguard() {
- startTransitionTo(KeyguardState.GONE)
+ scope.launch { startTransitionTo(KeyguardState.GONE) }
}
private fun listenForLockscreenToGone() {
@@ -298,9 +311,9 @@
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 @@
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 @@
}
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 @@
}
}
+ /**
+ * 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 @@
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 6a8555c..40061f4 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 @@
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.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 @@
@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 @@
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 @@
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 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -111,7 +117,7 @@
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -135,7 +141,7 @@
powerInteractor.isAsleep
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -154,7 +160,7 @@
private fun listenForOccludedToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isAlternateBouncerShowing, lastStartedTransitionStep) ->
if (
isAlternateBouncerShowing &&
@@ -183,6 +189,7 @@
}
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 5f246e1..c62055f 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 @@
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.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 @@
@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 @@
) :
TransitionInteractor(
fromState = KeyguardState.PRIMARY_BOUNCER,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -115,7 +122,7 @@
.distinctUntilChanged()
fun dismissPrimaryBouncer() {
- startTransitionTo(KeyguardState.GONE)
+ scope.launch { startTransitionTo(KeyguardState.GONE) }
}
private fun listenForPrimaryBouncerToLockscreenOrOccluded() {
@@ -124,7 +131,7 @@
.sample(
combine(
powerInteractor.isAwake,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
keyguardInteractor.isActiveDreamLockscreenHosted,
::toQuad
@@ -158,7 +165,7 @@
.sample(
combine(
powerInteractor.isAsleep,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Triple
),
@@ -185,7 +192,7 @@
.sample(
combine(
keyguardInteractor.isActiveDreamLockscreenHosted,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -213,7 +220,7 @@
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 0000000..cb50839
--- /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 f7d1543..a8223ea 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.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 @@
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 @@
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 fbf6936..19d00cf 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.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 @@
private val lightRevealScrimRepository: LightRevealScrimRepository,
@Application private val scope: CoroutineScope,
private val scrimLogger: ScrimLogger,
+ powerInteractor: PowerInteractor,
) {
init {
@@ -73,7 +77,16 @@
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 d5ac283..5c2df45 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.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 @@
*/
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 @@
)
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 cf1d247..4abda74 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 @@
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.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 @@
@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")
+ }
- inner class SharedFlowBuilder(
+ return FlowBuilder(duration, Edge(from, to))
+ }
+
+ 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 @@
}?.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 @@
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 05fe0b2..bf763b4 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.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 @@
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 @@
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 92270ad..81ce8f0 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.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 @@
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 920fc04..fab60e8 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 @@
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 @@
@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 f2b28d9..f33aed0 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 @@
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 9b40433..d118d4d 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.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 @@
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 @@
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 0f8e673..756a4cc 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.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.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 @@
notificationStackSizeCalculator: NotificationStackSizeCalculator,
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
@Main mainDispatcher: CoroutineDispatcher,
+ private val largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
) :
NotificationStackScrollLayoutSection(
context,
@@ -72,7 +76,13 @@
}
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 a8e3be7..b4b48a8 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 @@
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 @@
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 5d6b0ce..3737e6f 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 @@
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 @@
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 0000000..7592881
--- /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 fa4de04..ce45112 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 @@
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 8e729f7..2526f0a 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 @@
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 @@
@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 @@
animationFlow
.setup(
duration = TRANSITION_DURATION_MS,
- stepFlow = transitionInteractor.anyStateToAlternateBouncerTransition,
+ from = null,
+ to = ALTERNATE_BOUNCER,
)
.sharedFlow(
duration = TRANSITION_DURATION_MS,
@@ -60,7 +59,8 @@
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 2b14521..b92a9a0 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 @@
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 @@
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 5e552e1..266fd02 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 @@
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 @@
class AodToLockscreenTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {
@@ -45,7 +44,8 @@
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 d283af3..105a7ed 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 @@
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 @@
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 41dc157..924fc5d 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.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 @@
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 @@
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 fe0b365..310ec95 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 @@
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 @@
@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 @@
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 0b34326..e4610c1 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 @@
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 @@
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 8bcf3f8..67568e1 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 @@
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 @@
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 5f620af..ead2d48 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.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 @@
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 0000000..bc51821
--- /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 3f27eb0..ba04fd3 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.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 @@
class GoneToAodTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {
@@ -44,7 +43,8 @@
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 bba790a..b527463 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 @@
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 @@
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 6762ba6..102242a 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 @@
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 @@
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 adae8ab..793abb4 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 @@
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 @@
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 5059e6b..5d36da9 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.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
@@ -58,6 +59,8 @@
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel,
+ glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel,
screenOffAnimationController: ScreenOffAnimationController,
private val aodBurnInViewModel: AodBurnInViewModel,
aodAlphaViewModel: AodAlphaViewModel,
@@ -78,7 +81,13 @@
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 65614f4..7bf51a7 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 @@
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 @@
class LockscreenToAodTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
shadeDependentFlows: ShadeDependentFlows,
animationFlow: KeyguardTransitionAnimationFlow,
@@ -45,7 +44,8 @@
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 accb20c..4c0cd2f 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 @@
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 @@
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 c649b12..19b9cf47 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 @@
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 @@
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 7f75b54..13522a6 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 @@
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 @@
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 0000000..3ea83ae
--- /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 9e19713..a26ef07 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 @@
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 @@
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 9db0b77..dd6652e 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.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 @@
class LockscreenToOccludedTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
shadeDependentFlows: ShadeDependentFlows,
configurationInteractor: ConfigurationInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
@@ -46,7 +45,8 @@
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 52e3257..ce47f3c6 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 @@
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 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 @@
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 ed5e83c..07c1141 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 @@
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 @@
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 4c24f83..90195bd 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.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 @@
class OccludedToLockscreenTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
configurationInteractor: ConfigurationInteractor,
animationFlow: KeyguardTransitionAnimationFlow,
@@ -50,7 +49,8 @@
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 93482ea..74094be 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 @@
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 b0e2aa2..cd8e2f1 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 @@
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 @@
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 9dbe97f..4f28b46 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.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 @@
class PrimaryBouncerToGoneTransitionViewModel
@Inject
constructor(
- interactor: KeyguardTransitionInteractor,
private val statusBarStateController: SysuiStatusBarStateController,
private val primaryBouncerInteractor: PrimaryBouncerInteractor,
keyguardDismissActionInteractor: Lazy<KeyguardDismissActionInteractor>,
@@ -55,7 +53,8 @@
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 b2eed60..284a134 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 @@
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.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 @@
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 @@
}
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 2551da8..5720cc7 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.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 @@
private String mCurrentBroadcastApp;
private MultiRippleController mMultiRippleController;
private TurbulenceNoiseController mTurbulenceNoiseController;
- private final FeatureFlags mFeatureFlags;
private final GlobalSettings mGlobalSettings;
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
@@ -281,7 +278,6 @@
ActivityIntentHelper activityIntentHelper,
NotificationLockscreenUserManager lockscreenUserManager,
BroadcastDialogController broadcastDialogController,
- FeatureFlags featureFlags,
GlobalSettings globalSettings,
MediaFlags mediaFlags
) {
@@ -312,8 +308,6 @@
return Unit.INSTANCE;
});
- mFeatureFlags = featureFlags;
-
mGlobalSettings = globalSettings;
updateAnimatorDurationScale();
}
@@ -1187,9 +1181,7 @@
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 @@
}
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 0385aeb..523414c 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 @@
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 0320dec..092f1ed 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 @@
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 @@
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 62c7343..0167287 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 @@
}
@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/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index e660b97..0d641ac 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -758,7 +758,8 @@
}
private void updateMLModelState() {
- boolean newState = mIsGestureHandlingEnabled && DeviceConfig.getBoolean(
+ boolean newState = mIsGestureHandlingEnabled && mContext.getResources().getBoolean(
+ R.bool.config_useBackGestureML) && DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.USE_BACK_GESTURE_ML_MODEL, false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 0644237..a3b9254 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 @@
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 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 @@
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 fc06090..fe10eaa 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 @@
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 @@
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 @@
}
// 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 afca57c..0ad520b 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 @@
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 @@
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 45917e8..fd53423 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 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 bd43307..7aa0dad 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.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 @@
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 @@
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 3aab3bf..a170d0da 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 @@
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 @@
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 @@
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 3be60b7..782d651 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 0000000..c74f038
--- /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 a5c1cf1..aeccf00 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.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 @@
.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 @@
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 @@
} 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() {
@@ -4362,8 +4363,7 @@
@Override
public void onHeadsUpPinned(NotificationEntry entry) {
if (!isKeyguardShowing()) {
- mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
- entry.getHeadsUpAnimationView(), true);
+ mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, true);
}
}
@@ -4375,8 +4375,7 @@
// notification
// will stick to the top without any interaction.
if (isFullyCollapsed() && entry.isRowHeadsUp() && !isKeyguardShowing()) {
- mNotificationStackScrollLayoutController.generateHeadsUpAnimation(
- entry.getHeadsUpAnimationView(), false);
+ mNotificationStackScrollLayoutController.generateHeadsUpAnimation(entry, false);
entry.setHeadsUpIsVisible();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java
index 5fbb60d..60feb82 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 @@
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 @@
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 cde2a62..8c852cd 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 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.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.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 @@
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 @@
// 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 9c8a286..84cad1d 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.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.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 @@
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 @@
}
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 1dff99d..f3e9c75 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 @@
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 @@
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 @@
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 @@
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 2460a33..a66bacd 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 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 @@
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 7a340d2..6407b5a 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.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 @@
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 39b7930..6e85074 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 2438298..7f8be1c 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.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 @@
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 9b8dd0b..24ac70e 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.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.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 @@
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 @@
};
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 @@
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 @@
LockPatternUtils lockPatternUtils,
FeatureFlagsClassic featureFlags) {
mContext = context;
- mMainHandler = mainHandler;
- mBackgroundHandler = backgroundHandler;
+ mMainExecutor = mainExecutor;
mBackgroundExecutor = backgroundExecutor;
mDevicePolicyManager = devicePolicyManager;
mUserManager = userManager;
@@ -362,10 +358,10 @@
}
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 @@
}
};
- mSettingsObserver = new ContentObserver(mMainHandler) {
+ mSettingsObserver = new ExecutorContentObserver(mMainExecutor) {
@Override
public void onChange(boolean selfChange) {
updateLockscreenNotificationSetting();
@@ -468,14 +464,14 @@
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 @@
}
}
}
- mMainHandler.post(() -> {
+ mMainExecutor.execute(() -> {
for (UserChangedListener listener : mListeners) {
listener.onCurrentProfilesChanged(mCurrentProfiles);
}
@@ -895,7 +891,7 @@
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 29d53fc..9f878b2 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 @@
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 0000000..c0302bc
--- /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 0000000..68f727b
--- /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 31ca106..e200e65 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 @@
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 @@
}
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/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index f6431a2..7ea9b14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -32,6 +32,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.util.ContrastColorUtil;
+import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.res.R;
@@ -58,11 +60,19 @@
private int mExpandAnimationWidth = -1;
private int mExpandAnimationHeight = -1;
private int mDrawableAlpha = 255;
+ private final ColorStateList mLightColoredStatefulColors;
+ private final ColorStateList mDarkColoredStatefulColors;
+ private final int mNormalColor;
public NotificationBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
- mDontModifyCorners = getResources().getBoolean(
- R.bool.config_clipNotificationsToOutline);
+ mDontModifyCorners = getResources().getBoolean(R.bool.config_clipNotificationsToOutline);
+ mLightColoredStatefulColors = getResources().getColorStateList(
+ R.color.notification_state_color_light);
+ mDarkColoredStatefulColors = getResources().getColorStateList(
+ R.color.notification_state_color_dark);
+ mNormalColor = Utils.getColorAttrDefaultColor(mContext,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh);
}
@Override
@@ -122,6 +132,18 @@
}
/**
+ * Stateful colors are colors that will overlay on the notification original color when one of
+ * hover states, pressed states or other similar states is activated.
+ */
+ private void setStatefulColors() {
+ if (mTintColor != mNormalColor) {
+ ColorStateList newColor = ContrastColorUtil.isColorDark(mTintColor)
+ ? mDarkColoredStatefulColors : mLightColoredStatefulColors;
+ ((GradientDrawable) getStatefulBackgroundLayer().mutate()).setColor(newColor);
+ }
+ }
+
+ /**
* Sets a background drawable. As we need to change our bounds independently of layout, we need
* the notion of a background independently of the regular View background..
*/
@@ -149,21 +171,20 @@
setCustomBackground(d);
}
- public void setTint(int tintColor) {
- if (tintColor != 0) {
- ColorStateList stateList = new ColorStateList(new int[][]{
- new int[]{com.android.internal.R.attr.state_pressed},
- new int[]{com.android.internal.R.attr.state_hovered},
- new int[]{}},
+ private Drawable getBaseBackgroundLayer() {
+ return ((LayerDrawable) mBackground).getDrawable(0);
+ }
- new int[]{tintColor, 0, tintColor}
- );
- mBackground.setTintMode(PorterDuff.Mode.SRC_ATOP);
- mBackground.setTintList(stateList);
- } else {
- mBackground.setTintList(null);
- }
+ private Drawable getStatefulBackgroundLayer() {
+ return ((LayerDrawable) mBackground).getDrawable(1);
+ }
+
+ public void setTint(int tintColor) {
+ Drawable baseLayer = getBaseBackgroundLayer();
+ baseLayer.mutate().setTintMode(PorterDuff.Mode.SRC_ATOP);
+ baseLayer.setTint(tintColor);
mTintColor = tintColor;
+ setStatefulColors();
invalidate();
}
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 6528cef3..a1718b9 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.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 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 @@
// forceUpdateVisibilities cancels outstanding animations without updating the
// mAnimationStartVisibleType. Do so here instead.
mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
+ notifySubtreeForAccessibilityContentChange();
}
private void fireExpandedVisibleListenerIfVisible() {
@@ -980,6 +982,7 @@
// 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 @@
hiddenView.setVisible(false);
}
mAnimationStartVisibleType = VISIBLE_TYPE_NONE;
+ notifySubtreeForAccessibilityContentChange();
}
});
fireExpandedVisibleListenerIfVisible();
@@ -1049,6 +1053,22 @@
}
}
+ @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 @@
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/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 805b44c..ea414d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4869,10 +4869,6 @@
public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
- generateHeadsUpAnimation(row, isHeadsUp);
- }
-
- public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
final boolean add = mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed);
if (SPEW) {
Log.v(TAG, "generateHeadsUpAnimation:"
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 2e54512..a30c294 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.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;
@@ -1495,14 +1496,10 @@
return mView.getFirstChildNotGone();
}
- private void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
+ public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
mView.generateHeadsUpAnimation(entry, isHeadsUp);
}
- public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
- mView.generateHeadsUpAnimation(row, isHeadsUp);
- }
-
public void setMaxTopPadding(int padding) {
mView.setMaxTopPadding(padding);
}
@@ -1961,18 +1958,34 @@
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 625fdc1..4b8fb1e 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 @@
private val splitShadeStateController: SplitShadeStateController,
keyguardInteractor: KeyguardInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+ largeScreenHeaderHelperLazy: Lazy<LargeScreenHeaderHelper>,
) {
private val _topPosition = MutableStateFlow(0f)
@@ -72,7 +76,11 @@
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 0bad47e..8a45ec1 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 @@
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 @@
}
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 @@
// 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 0a03af7..ca3e3c6 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.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 @@
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 7cc0888..7691459 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 @@
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 @@
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 30a445f..703b3c6 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 @@
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 89a2fb7..e309c32 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.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.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 39135c7..d555c47 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.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 @@
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 @@
)
.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 8fc8b2f..de46a5e 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 @@
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 @@
// 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 3be14bc..10bf068 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 @@
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 5d69f36..9f4a906 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.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 @@
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 @@
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 @@
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 @@
}
@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 @@
@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 @@
}
}
};
+
+ /**
+ * 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
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt
index 91886bb..2a0812b 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.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 @@
@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 0000000..ca36e39
--- /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 8d85999..0000000
--- 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 ce1a2e9..0000000
--- 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 20fef92..e57c0e7 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 @@
if (DEBUG) {
Log.i(TAG, "onSurfaceDestroyed");
}
- mSurfaceHolder = null;
+ mLongExecutor.execute(this::onSurfaceDestroyedSynchronized);
+ }
+
+ private void onSurfaceDestroyedSynchronized() {
+ synchronized (mLock) {
+ mSurfaceHolder = null;
+ }
}
@Override
@@ -241,7 +247,7 @@
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/WindowMagnificationAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
index 837a130..2afb3a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationAnimationControllerTest.java
@@ -43,7 +43,6 @@
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
import android.view.animation.AccelerateInterpolator;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.LargeTest;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
@@ -68,7 +67,6 @@
@LargeTest
@RunWith(AndroidTestingRunner.class)
-@FlakyTest(bugId = 308501761)
public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
@Rule
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 0000000..9dd337e
--- /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 be6f3ff..68879a5 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.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.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.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 @@
@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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
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 9e3c576..bd4973d 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 @@
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 @@
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 6170e0c..bf61c2e 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 @@
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.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.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 @@
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 @@
selector =
PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils)
selector.resetPrompt()
+ promptContentView =
+ PromptVerticalListContentView.Builder()
+ .addListItem(PromptContentListItemBulletedText("test"))
+ .build()
viewModel =
PromptViewModel(
@@ -1200,6 +1206,26 @@
}
}
+ @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 @@
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 @@
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 @@
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 c4df27c..cb8c40c 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.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 @@
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 @@
DeviceEntrySideFpsOverlayInteractor(
testScope.backgroundScope,
mContext,
- FakeDeviceEntryFingerprintAuthRepository(),
+ deviceEntryFingerprintAuthRepository,
primaryBouncerInteractor,
alternateBouncerInteractor,
keyguardUpdateMonitor
@@ -216,6 +218,30 @@
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 8e81185..809947d 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 @@
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 b8a8bdf..0ea4e9f 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 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.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 @@
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 @@
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 @@
)
.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 @@
fromPrimaryBouncerTransitionInteractor =
FromPrimaryBouncerTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -173,6 +199,8 @@
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -182,6 +210,8 @@
fromDreamingLockscreenHostedTransitionInteractor =
FromDreamingLockscreenHostedTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -191,6 +221,8 @@
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -200,6 +232,8 @@
fromGoneTransitionInteractor =
FromGoneTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -210,6 +244,8 @@
fromDozingTransitionInteractor =
FromDozingTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -220,6 +256,8 @@
fromOccludedTransitionInteractor =
FromOccludedTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -230,12 +268,24 @@
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 @@
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 edd781d..2d9d5ed 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 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 @@
@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 @@
onFinish = { 10f },
)
var animationValues = collectLastValue(flow)
+ runCurrent()
+
repository.sendTransitionStep(step(1f, TransitionState.FINISHED), validateStep = false)
assertThat(animationValues()).isEqualTo(10f)
}
@@ -97,6 +99,8 @@
onCancel = { 100f },
)
var animationValues = collectLastValue(flow)
+ runCurrent()
+
repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
assertThat(animationValues()).isEqualTo(100f)
}
@@ -111,6 +115,8 @@
onStep = { it },
)
var animationValues = collectLastValue(flow)
+ runCurrent()
+
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
assertThat(animationValues()).isEqualTo(0f)
@@ -137,6 +143,8 @@
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 @@
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 d959872..87391cc 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.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 @@
fun transitionToAlternateBouncer_scrimAlphaUpdate() =
testScope.runTest {
val scrimAlphas by collectValues(underTest.scrimAlpha)
+ runCurrent()
transitionRepository.sendTransitionSteps(
listOf(
@@ -69,17 +71,17 @@
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 af8d8a8..795e68d 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.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 @@
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 daafe12..75994da 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.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 @@
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 @@
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 @@
fun scrimBehindAlpha_leaveShadeOpen() =
testScope.runTest {
val values by collectValues(underTest.scrimAlpha(500.milliseconds, PRIMARY_BOUNCER))
+ runCurrent()
sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true)
@@ -146,6 +152,8 @@
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 dd542d4..471029b 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.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 @@
@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 a105008..1c9c942 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.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 @@
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 @@
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 @@
testScope.runTest {
val deviceEntryBackgroundViewAlpha by
collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ runCurrent()
// immediately 0f
repository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -113,6 +117,7 @@
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 @@
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 @@
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 5e62317..1912987 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.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 @@
testScope.runTest {
val deviceEntryBackgroundViewAlpha by
collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ runCurrent()
// immediately 0f
keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -72,6 +74,7 @@
fingerprintPropertyRepository.supportsUdfps()
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ runCurrent()
// immediately 1f
keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -96,6 +99,7 @@
fingerprintPropertyRepository.supportsRearFps()
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ runCurrent()
// no updates
keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -120,6 +124,7 @@
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 9729022..c55c27c 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.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 @@
fingerprintPropertyRepository.supportsUdfps()
val deviceEntryBackgroundViewAlpha by
collectLastValue(underTest.deviceEntryBackgroundViewAlpha)
+ runCurrent()
// immediately 0f
keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -75,6 +77,7 @@
fingerprintPropertyRepository.supportsUdfps()
biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
val deviceEntryParentViewAlpha by collectLastValue(underTest.deviceEntryParentViewAlpha)
+ runCurrent()
keyguardTransitionRepository.sendTransitionStep(step(0f, TransitionState.STARTED))
@@ -92,6 +95,7 @@
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 @@
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 2c6436e..0796af0 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.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 @@
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 2f35380..5996502 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.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 @@
@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 @@
activityIntentHelper,
lockscreenUserManager,
broadcastDialogController,
- fakeFeatureFlag,
globalSettings,
mediaFlags,
) {
@@ -2397,8 +2389,7 @@
}
@Test
- fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
- fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
+ fun onButtonClick_playsTouchRipple() {
val semanticActions =
MediaButton(
playOrPause =
@@ -2419,31 +2410,7 @@
}
@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 @@
@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 5569ca9..b7a9ea7 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.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 @@
@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 @@
communalInteractor,
communalViewModel,
keyguardTransitionInteractor,
- shadeInteractor
+ shadeInteractor,
+ powerManager
)
testableLooper = TestableLooper.get(this)
@@ -90,14 +95,14 @@
}
@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 @@
}
@Test
- fun onTouchEvent_touchInsideGestureRegion_returnsTrue() {
+ fun onTouchEvent_touchInsideGestureRegion_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -131,7 +136,7 @@
}
@Test
- fun onTouchEvent_subsequentTouchesAfterGestureStart_returnsTrue() {
+ fun onTouchEvent_subsequentTouchesAfterGestureStart_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -146,7 +151,7 @@
}
@Test
- fun onTouchEvent_communalOpen_returnsTrue() {
+ fun onTouchEvent_communalOpen_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -155,10 +160,12 @@
// 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 @@
// 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 a206581..49579f6 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.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.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 @@
@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 @@
mContext,
new ResourcesSplitShadeStateController(),
mKeyguardInteractor,
- deviceEntryUdfpsInteractor
+ deviceEntryUdfpsInteractor,
+ () -> mLargeScreenHeaderHelper
),
mShadeRepository
)
@@ -812,7 +814,8 @@
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 9d8b214..791c080 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 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.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.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.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.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 @@
@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 @@
new ConfigurationInteractor(configurationRepository),
shadeRepository,
() -> sceneInteractor);
+ CommunalInteractor communalInteractor =
+ CommunalInteractorFactory.create().getCommunalInteractor();
FakeKeyguardTransitionRepository keyguardTransitionRepository =
new FakeKeyguardTransitionRepository();
@@ -215,10 +221,18 @@
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 @@
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mKeyguardSecurityModel,
@@ -261,7 +277,8 @@
mContext,
new ResourcesSplitShadeStateController(),
keyguardInteractor,
- deviceEntryUdfpsInteractor),
+ deviceEntryUdfpsInteractor,
+ () -> mLargeScreenHeaderHelper),
shadeRepository
)
);
@@ -519,8 +536,8 @@
@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 @@
}
@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 @@
@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 ee7c6c8..a11839c 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.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.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.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 @@
@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 @@
@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 @@
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 33d60ea..0c4bf81 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.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 @@
@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 @@
@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 @@
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 88a47eb..ea3caa3 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.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.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 @@
@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 @@
delayableExecutor,
featureFlags,
notificationStackScrollLayoutController,
- ResourcesSplitShadeStateController()
+ ResourcesSplitShadeStateController(),
+ largeScreenHeaderHelperLazy = { largeScreenHeaderHelper }
)
overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
@@ -480,7 +482,8 @@
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 1f37ca0..c1bc303 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.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.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 @@
@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 @@
delayableExecutor,
featureFlags,
notificationStackScrollLayoutController,
- ResourcesSplitShadeStateController()
+ ResourcesSplitShadeStateController(),
+ largeScreenHeaderHelperLazy = { largeScreenHeaderHelper }
)
overrideResource(R.dimen.split_shade_notifications_scrim_margin_bottom, SCRIM_MARGIN)
@@ -463,7 +465,8 @@
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 727a6c3..a369f82 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.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.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.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 @@
@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 @@
new ConfigurationInteractor(configurationRepository),
mShadeRepository,
() -> sceneInteractor);
+ CommunalInteractor communalInteractor =
+ CommunalInteractorFactory.create().getCommunalInteractor();
FakeKeyguardTransitionRepository keyguardTransitionRepository =
new FakeKeyguardTransitionRepository();
@@ -250,10 +256,18 @@
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 @@
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mock(KeyguardSecurityModel.class),
@@ -299,7 +315,8 @@
mContext,
splitShadeStateController,
keyguardInteractor,
- deviceEntryUdfpsInteractor),
+ deviceEntryUdfpsInteractor,
+ () -> mLargeScreenHeaderHelper),
mShadeRepository
)
);
@@ -384,7 +401,8 @@
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 65e0fa1..71a7420 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.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 @@
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 @@
fun isExpandToQsEnabled_shadeNotEnabled_false() =
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
DisableFlagsModel(
@@ -191,7 +191,7 @@
fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
DisableFlagsModel(
@@ -206,7 +206,7 @@
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 @@
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -262,7 +262,7 @@
DisableFlagsModel(
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -290,7 +290,7 @@
DisableFlagsModel(
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -322,21 +322,21 @@
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 ee27c5c..64fd80d 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.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 @@
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 bc50c25..3defee9 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 @@
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 f25ce0a..4a365b9 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.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.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.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.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 @@
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 @@
{ 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 @@
keyguardTransitionRepository,
keyguardTransitionInteractor,
testScope.backgroundScope,
+ testDispatcher,
+ testDispatcher,
keyguardInteractor,
featureFlags,
mock(),
@@ -189,6 +204,7 @@
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 5549fee..91e4666 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.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.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 @@
@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 @@
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 @@
}
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.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 83ba684..a172120 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 @@
@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 @@
@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 @@
@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 @@
@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 3556703..4dc4798 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 @@
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 @@
.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 @@
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 @@
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 91c233a..0000000
--- 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 2060288..0b14be1 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.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 52fc258..889130f 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.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.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 44fa132..147efcb 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.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.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 a906a89..02e6fd5 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_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 @@
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 89842d6..f63f79f 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.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 @@
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 1bdf644..0cb3329 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.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.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 1dab84e..cb6ce68 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 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 6714c94..fb5375a 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 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 @@
)
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 @@
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 @@
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 @@
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 814ea19..8920d4d 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.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.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.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.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.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 @@
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 @@
() -> 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 @@
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mock(KeyguardSecurityModel.class),
@@ -490,7 +508,8 @@
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 e24ba26..c2dc673 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 @@
@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 b28af46..fdb9b30 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.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 @@
@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 0000000..4a089d3
--- /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 0000000..e262066
--- /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 ff5179a..8010261 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 @@
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 @@
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/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryKosmos.kt
similarity index 65%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryKosmos.kt
index 7b9634a..7946446 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/communal/data/repository/CommunalMediaRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.communal.data.repository
import com.android.systemui.kosmos.Kosmos
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalRepositoryKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/CommunalRepositoryKosmos.kt
index 7b9634a..be56d2b 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/communal/data/repository/CommunalRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.communal.data.repository
import com.android.systemui.kosmos.Kosmos
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 0000000..5a17f2f8
--- /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 eb287ee..95ff889 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 @@
@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 @@
communalRepository = communalRepository,
)
return WithDependencies(
+ testScope,
communalRepository,
widgetRepository,
mediaRepository,
@@ -74,6 +76,7 @@
}
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/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayRepositoryKosmos.kt
index 7b9634a..048ea3c 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/display/data/repository/DisplayRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.display.data.repository
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+val Kosmos.displayRepository by Fixture { FakeDisplayRepository() }
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/display/data/repository/DisplayStateRepositoryKosmos.kt
similarity index 65%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/DisplayStateRepositoryKosmos.kt
index 7b9634a..4a71a09 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/display/data/repository/DisplayStateRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+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
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 1d44929..93e0b41 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 @@
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 a94ca29..0c1dbfe 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 @@
)
}
}
-
_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 0000000..59f0ec3
--- /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 b03d0b8..3b38342 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.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 @@
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 ade3e1a..97536e2 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.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 @@
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 0000000..294b5ba
--- /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 8d6529a..dad1887 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 @@
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 d9c6e4f..3ed9392 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 @@
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 e4821b0..c909dd6 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 @@
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 0000000..2d1f836
--- /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 9f0466d..b4f1218 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 @@
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 44e5426..b6f278c 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 @@
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 b5a5f03..733340c 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 @@
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 27ad0f0..8d066fc 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 @@
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 6ffcc9a..c71c1c3 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 @@
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 @@
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 4bfe4f5..4f638d0 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 @@
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 @@
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 0000000..400a0d8
--- /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 0000000..28fce77
--- /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 00ece14..19e4241 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 @@
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 073b34b..b267a96 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 @@
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 933f50c..5564767 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 @@
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 7865f71..07b4cd4 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 @@
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 b9f4b71..56d5ff6 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 @@
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 0000000..9fe4ea3
--- /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 475aa2d..1b2337f 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 @@
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 8541a4f..9953d39 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 @@
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 65c47fc..f094f22 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 @@
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 ddde549..b7867b6 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 @@
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 93ecb79..e6651a4 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 @@
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 @@
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 a7f29d6..8d88730 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 @@
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 ace6ae3..ab28d0d6 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 @@
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 @@
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 3bbabf7..8566251 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 @@
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 1185f2e..0307c41 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 @@
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/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/LargeScreenHeaderHelperKosmos.kt
similarity index 68%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/shade/LargeScreenHeaderHelperKosmos.kt
index 7b9634a..d3e7574 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/shade/LargeScreenHeaderHelperKosmos.kt
@@ -14,9 +14,11 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+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.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 7da57f0..afd37b3 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.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/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/smartspace/data/repository/SmartspaceRepositoryKosmos.kt
index 7b9634a..e671d45 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/smartspace/data/repository/SmartspaceRepositoryKosmos.kt
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.smartspace.data.repository
import com.android.systemui.kosmos.Kosmos
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
rename to 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/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt
similarity index 67%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt
index 7b9634a..c416ea1 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/data/repository/FakeRemoteInputRepository.kt
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.data.repository
-import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.flow.MutableStateFlow
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+class FakeRemoteInputRepository : RemoteInputRepository {
+ override val isRemoteInputActive = MutableStateFlow(false)
+}
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/data/repository/RemoteInputRepositoryKosmos.kt
similarity index 72%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt
index 7b9634a..1684efb 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/data/repository/RemoteInputRepositoryKosmos.kt
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.data.repository
import com.android.systemui.kosmos.Kosmos
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt
similarity index 72%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt
index 7b9634a..07b39dc 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/domain/interactor/RemoteInputInteractorKosmos.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.data.repository.remoteInputRepository
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 13d577b..8909d75 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.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 @@
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 44f3134..f5a4c03 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.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 549929c..6e2d12a 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
similarity index 100%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
rename to 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
similarity index 97%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index a9ee405..de6c87c2 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 @@
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 021e7df..ac90a45 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 @@
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 @@
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
similarity index 85%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt
index 55e81bb..76a9861 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 @@
@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
similarity index 92%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt
index 7b9634a..a1c5b9a 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/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt
similarity index 72%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt
index 7b9634a..83f4939 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/domain/interactor/UserSetupInteractorKosmos.kt
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.policy.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
-var Kosmos.userSetupRepository: UserSetupRepository by Kosmos.Fixture { fakeUserSetupRepository }
-val Kosmos.fakeUserSetupRepository by Kosmos.Fixture { FakeUserSetupRepository() }
+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 76199e3..791165d 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 @@
}
@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 e52cefb..81fd8ce 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -39,7 +39,4 @@
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 449ed2e..0000000
--- 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 1fc74f7..67a7d12 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 @@
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 b403a7f..7f542d1 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -408,5 +408,9 @@
// 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/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index 513c095..d967874 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -142,6 +142,11 @@
Assume.assumeFalse(IS_UNDER_RAVENWOOD);
}
+ // Stopgap for http://g/ravenwood/EPAD-N5ntxM
+ if (description.getMethodName().endsWith("$noRavenwood")) {
+ Assume.assumeFalse(IS_UNDER_RAVENWOOD);
+ }
+
RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
base.evaluate();
diff --git a/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java b/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java
index 085c186..7abfecf 100644
--- a/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java
+++ b/ravenwood/minimum-test/test/com/android/ravenwood/RavenwoodMinimumTest.java
@@ -42,4 +42,9 @@
public void testIgnored() {
throw new RuntimeException("Shouldn't be executed under ravenwood");
}
+
+ @Test
+ public void testIgnored$noRavenwood() {
+ throw new RuntimeException("Shouldn't be executed under ravenwood");
+ }
}
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 491ed22..ab2546b 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -9,8 +9,10 @@
com.android.internal.os.LongArrayMultiStateCounter
com.android.internal.os.LongArrayMultiStateCounter$LongArrayContainer
com.android.internal.os.MonotonicClock
+com.android.internal.os.PowerProfile
com.android.internal.os.PowerStats
com.android.internal.os.PowerStats$Descriptor
+com.android.internal.power.ModemPowerProfile
android.util.AtomicFile
android.util.DataUnit
@@ -32,11 +34,16 @@
android.util.TimeUtils
android.util.Xml
+android.os.AggregateBatteryConsumer
android.os.BatteryConsumer
+android.os.BatteryStats
android.os.BatteryStats$HistoryItem
android.os.BatteryStats$HistoryStepDetails
android.os.BatteryStats$HistoryTag
+android.os.BatteryStats$LongCounter
android.os.BatteryStats$ProcessStateChange
+android.os.BatteryUsageStats
+android.os.BatteryUsageStatsQuery
android.os.Binder
android.os.Binder$IdentitySupplier
android.os.Broadcaster
@@ -54,11 +61,14 @@
android.os.PackageTagsList
android.os.Parcel
android.os.Parcelable
+android.os.PowerComponents
android.os.Process
android.os.ServiceSpecificException
android.os.SystemClock
android.os.ThreadLocalWorkSource
android.os.TimestampedValue
+android.os.UidBatteryConsumer
+android.os.UidBatteryConsumer$Builder
android.os.UserHandle
android.os.WorkSource
@@ -117,6 +127,7 @@
android.content.ContentProvider
com.android.server.LocalServices
+com.android.server.power.stats.BatteryStatsImpl
com.android.internal.util.BitUtils
com.android.internal.util.BitwiseInputStream
diff --git a/services/Android.bp b/services/Android.bp
index 0b484f4..7e8333c 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -148,9 +148,6 @@
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 a354671..69cc68a 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -22,6 +22,7 @@
lint: {
error_checks: ["MissingPermissionAnnotation"],
baseline_filename: "lint-baseline.xml",
+
},
srcs: [
":services.accessibility-sources",
@@ -50,9 +51,6 @@
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 6bec8cf..b808219 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 cab2d74..5407af7 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 @@
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 @@
boolean added = false;
boolean changed = false;
boolean componentsModified = false;
+ int clearedUid = -1;
final String pkgList[];
switch (action) {
@@ -416,6 +418,10 @@
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 @@
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 @@
}
}
}
+ } 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 @@
}
}
+ @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 @@
}
}
+ @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 @@
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 @@
return false;
}
- @GuardedBy("AppWidgetServiceImpl.mLock")
+ @GuardedBy("this.mLock")
public AppWidgetProviderInfo getInfoLocked(Context context) {
if (!mInfoParsed) {
// parse
@@ -4250,6 +4395,7 @@
}
if (newInfo != null) {
info = newInfo;
+ updateGeneratedPreviewCategoriesLocked();
}
}
mInfoParsed = true;
@@ -4279,6 +4425,62 @@
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/SecondaryProviderHandler.java b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
index 553ba12..7fc1738 100644
--- a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
+++ b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
@@ -16,6 +16,7 @@
package com.android.server.autofill;
+import static com.android.server.autofill.Session.REQUEST_ID_KEY;
import static com.android.server.autofill.Session.SESSION_ID_KEY;
import android.annotation.NonNull;
@@ -107,15 +108,16 @@
mLastFlag = flag;
if (mRemoteFillService != null && mRemoteFillService.isCredentialAutofillService()) {
Slog.v(TAG, "About to call CredAutofill service as secondary provider");
- addSessionIdToClientState(pendingFillRequest, pendingInlineSuggestionsRequest, id);
+ addSessionIdAndRequestIdToClientState(pendingFillRequest,
+ pendingInlineSuggestionsRequest, id);
mRemoteFillService.onFillCredentialRequest(pendingFillRequest, client);
} else {
mRemoteFillService.onFillRequest(pendingFillRequest);
}
}
- private FillRequest addSessionIdToClientState(FillRequest pendingFillRequest,
- InlineSuggestionsRequest pendingInlineSuggestionsRequest, int id) {
+ private FillRequest addSessionIdAndRequestIdToClientState(FillRequest pendingFillRequest,
+ InlineSuggestionsRequest pendingInlineSuggestionsRequest, int sessionId) {
if (pendingFillRequest.getClientState() == null) {
pendingFillRequest = new FillRequest(pendingFillRequest.getId(),
pendingFillRequest.getFillContexts(),
@@ -125,7 +127,8 @@
pendingInlineSuggestionsRequest,
pendingFillRequest.getDelayedFillIntentSender());
}
- pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, id);
+ pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, sessionId);
+ pendingFillRequest.getClientState().putInt(REQUEST_ID_KEY, pendingFillRequest.getId());
return pendingFillRequest;
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 007be05..6a81425 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -234,7 +234,8 @@
new ComponentName("com.android.credentialmanager",
"com.android.credentialmanager.autofill.CredentialAutofillService");
- static final String SESSION_ID_KEY = "session_id";
+ static final String SESSION_ID_KEY = "autofill_session_id";
+ static final String REQUEST_ID_KEY = "autofill_request_id";
final Object mLock;
@@ -729,7 +730,7 @@
mPendingFillRequest.getFlags(), id, mClient);
} else if (mRemoteFillService != null) {
if (mIsPrimaryCredential) {
- mPendingFillRequest = addSessionIdToClientState(mPendingFillRequest,
+ mPendingFillRequest = addSessionIdAndRequestIdToClientState(mPendingFillRequest,
mPendingInlineSuggestionsRequest, id);
mRemoteFillService.onFillCredentialRequest(mPendingFillRequest, mClient);
} else {
@@ -877,8 +878,8 @@
}
}
- private FillRequest addSessionIdToClientState(FillRequest pendingFillRequest,
- InlineSuggestionsRequest pendingInlineSuggestionsRequest, int id) {
+ private FillRequest addSessionIdAndRequestIdToClientState(FillRequest pendingFillRequest,
+ InlineSuggestionsRequest pendingInlineSuggestionsRequest, int sessionId) {
if (pendingFillRequest.getClientState() == null) {
pendingFillRequest = new FillRequest(pendingFillRequest.getId(),
pendingFillRequest.getFillContexts(),
@@ -888,7 +889,8 @@
pendingInlineSuggestionsRequest,
pendingFillRequest.getDelayedFillIntentSender());
}
- pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, id);
+ pendingFillRequest.getClientState().putInt(SESSION_ID_KEY, sessionId);
+ pendingFillRequest.getClientState().putInt(REQUEST_ID_KEY, pendingFillRequest.getId());
return pendingFillRequest;
}
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index d695d36..549fa36 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -7,4 +7,12 @@
"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 6aed9aa..cca166b 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 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 @@
// 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 ff72476..2c9eb51 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.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.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 @@
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 316a16d..2fbc3cd 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 @@
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 @@
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 1c0cd87..843354e 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 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 @@
// 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 0accb9f..5a8533a 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 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 @@
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 93c9390..46de2cdd 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 4b3772a..d0eb59d 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.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 @@
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 4e471f5..260b21f 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_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.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 @@
}
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 720687e..0e66fbc 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.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 62c6703..3e45626 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 @@
* 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 22b18ac..8a5774e 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 @@
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 1f89e57b..d1274d4 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 @@
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 58aa2c3..44c3a8d 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 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 03eae39..020126f 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 a3fc3bf..a6ed498 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -234,9 +234,6 @@
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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 19a9239..7a4ac6a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1356,8 +1356,8 @@
final int flags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
for (UserInfo user : users) {
- prepareUserStorageInternal(fromVolumeUuid, user.id, user.serialNumber, flags);
- prepareUserStorageInternal(toVolumeUuid, user.id, user.serialNumber, flags);
+ prepareUserStorageInternal(fromVolumeUuid, user.id, flags);
+ prepareUserStorageInternal(toVolumeUuid, user.id, flags);
}
}
@@ -3231,7 +3231,7 @@
@android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
@Override
- public void createUserStorageKeys(int userId, int serialNumber, boolean ephemeral) {
+ public void createUserStorageKeys(int userId, boolean ephemeral) {
super.createUserStorageKeys_enforcePermission();
@@ -3276,8 +3276,7 @@
/* Only for use by LockSettingsService */
@android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
@Override
- public void unlockCeStorage(@UserIdInt int userId, int serialNumber, byte[] secret)
- throws RemoteException {
+ public void unlockCeStorage(@UserIdInt int userId, byte[] secret) throws RemoteException {
super.unlockCeStorage_enforcePermission();
if (StorageManager.isFileEncrypted()) {
@@ -3348,25 +3347,25 @@
continue;
}
- prepareUserStorageInternal(vol.fsUuid, user.id, user.serialNumber, flags);
+ prepareUserStorageInternal(vol.fsUuid, user.id, flags);
}
}
@android.annotation.EnforcePermission(android.Manifest.permission.STORAGE_INTERNAL)
@Override
- public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
+ public void prepareUserStorage(String volumeUuid, int userId, int flags) {
super.prepareUserStorage_enforcePermission();
try {
- prepareUserStorageInternal(volumeUuid, userId, serialNumber, flags);
+ prepareUserStorageInternal(volumeUuid, userId, flags);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
- private void prepareUserStorageInternal(String volumeUuid, int userId, int serialNumber,
- int flags) throws Exception {
+ private void prepareUserStorageInternal(String volumeUuid, int userId, int flags)
+ throws Exception {
try {
mVold.prepareUserStorage(volumeUuid, userId, flags);
// After preparing user storage, we should check if we should mount data mirror again,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9eb35fd..eb6fdd7 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.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 @@
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 85abf87..130a733 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 @@
new AccountAuthenticatorResponse(this),
authTokenType,
true);
+ mCanStartAccountManagerActivity = true;
Bundle bundle = new Bundle();
bundle.putParcelable(AccountManager.KEY_INTENT, intent);
onResult(bundle);
@@ -4933,6 +4934,7 @@
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 @@
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 02f4485..0cff8b7 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 @@
}
}
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 @@
// 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 8ad60e6..72e62c3 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 @@
/**
* 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 fddb570..e583a6c 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 @@
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 @@
* 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 e0a2246..9fc0bf9 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 @@
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 @@
// 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 eea9337..c96c2ff 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 @@
}
};
- 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 @@
.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 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 095d907..30f21a6 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 @@
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 @@
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 @@
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/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 08b129e..2771572 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -39,7 +39,7 @@
import android.app.RemoteServiceException.CannotPostForegroundServiceNotificationException;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.Disabled;
+import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -49,6 +49,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.IBinder;
import android.os.PowerExemptionManager;
import android.os.SystemClock;
@@ -94,16 +95,14 @@
* (See also android.app.ForegroundServiceTypePolicy)
*/
@ChangeId
- // @EnabledAfter(targetSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
- @Disabled
+ @EnabledAfter(targetSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
static final long USE_NEW_WIU_LOGIC_FOR_START = 311208629L;
/**
* Compat ID to enable the new FGS start logic, for capability calculation.
*/
@ChangeId
- // Always enabled
- @Disabled
+ @EnabledAfter(targetSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
static final long USE_NEW_WIU_LOGIC_FOR_CAPABILITIES = 313677553L;
/**
@@ -111,8 +110,7 @@
* the background.
*/
@ChangeId
- // @EnabledAfter(targetSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
- @Disabled
+ @EnabledAfter(targetSdkVersion = VERSION_CODES.UPSIDE_DOWN_CAKE)
static final long USE_NEW_BFSL_LOGIC = 311208749L;
final ActivityManagerService ams;
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 9f31f37..5f12ce1 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 @@
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 dada72e..f80228a 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 @@
"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 e05824a..bf20ae3 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 @@
// 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 91d533c..4cbee2b 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 @@
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 @@
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 @@
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 a818c30..f51043d 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 @@
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 @@
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 c2bc1e4..a30cdc4 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.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 @@
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 @@
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 @@
mGlobalTimeOffsetInSecs);
if (records != null) {
mDoseRecords.addAll(records);
+ sanitizeDoseRecords_l();
}
}
}
@@ -1176,17 +1187,35 @@
&& 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 @@
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/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 89b638b..89e08c1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -16,6 +16,8 @@
package com.android.server.biometrics.sensors;
+import static com.android.server.biometrics.sensors.BiometricSchedulerOperation.STATE_STARTED;
+
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
@@ -28,6 +30,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -35,6 +38,7 @@
import com.android.modules.expresslog.Counter;
import com.android.server.biometrics.BiometricSchedulerProto;
import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.io.PrintWriter;
@@ -48,6 +52,7 @@
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* A scheduler for biometric HAL operations. Maintains a queue of {@link BaseClientMonitor}
@@ -56,11 +61,16 @@
*
* We currently assume (and require) that each biometric sensor have its own instance of a
* {@link BiometricScheduler}.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
+ *
+ * TODO: (b/304604965) Update thread annotation when FLAGS_DE_HIDL is removed.
*/
@MainThread
-public class BiometricScheduler {
+public class BiometricScheduler<T, U> {
- private static final String BASE_TAG = "BiometricScheduler";
+ private static final String TAG = "BiometricScheduler";
// Number of recent operations to keep in our logs for dumpsys
protected static final int LOG_NUM_RECENT_OPERATIONS = 50;
@@ -89,30 +99,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface SensorType {}
- public static @SensorType int sensorTypeFromFingerprintProperties(
- @NonNull FingerprintSensorPropertiesInternal props) {
- if (props.isAnyUdfpsType()) {
- return SENSOR_TYPE_UDFPS;
- }
-
- return SENSOR_TYPE_FP_OTHER;
- }
-
- public static String sensorTypeToString(@SensorType int sensorType) {
- switch (sensorType) {
- case SENSOR_TYPE_UNKNOWN:
- return "Unknown";
- case SENSOR_TYPE_FACE:
- return "Face";
- case SENSOR_TYPE_UDFPS:
- return "Udfps";
- case SENSOR_TYPE_FP_OTHER:
- return "OtherFp";
- default:
- return "UnknownUnknown";
- }
- }
-
private static final class CrashState {
static final int NUM_ENTRIES = 10;
final String timestamp;
@@ -145,8 +131,8 @@
}
}
- @NonNull protected final String mBiometricTag;
- private final @SensorType int mSensorType;
+ @SensorType
+ private final int mSensorType;
@Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@NonNull private final IBiometricService mBiometricService;
@NonNull protected final Handler mHandler;
@@ -157,6 +143,43 @@
private int mTotalOperationsHandled;
private final int mRecentOperationsLimit;
@NonNull private final List<Integer> mRecentOperations;
+ @Nullable private StopUserClient<U> mStopUserClient;
+ @NonNull private Supplier<Integer> mCurrentUserRetriever;
+ @Nullable private UserSwitchProvider<T, U> mUserSwitchProvider;
+
+ private class UserSwitchClientCallback implements ClientMonitorCallback {
+ @NonNull private final BaseClientMonitor mOwner;
+
+ UserSwitchClientCallback(@NonNull BaseClientMonitor owner) {
+ mOwner = owner;
+ }
+
+ @Override
+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
+ mHandler.post(() -> {
+ Slog.d(TAG, "[Client finished] " + clientMonitor + ", success: " + success);
+
+ // Set mStopUserClient to null when StopUserClient fails. Otherwise it's possible
+ // for that the queue will wait indefinitely until the field is cleared.
+ if (clientMonitor instanceof StopUserClient<?>) {
+ if (!success) {
+ Slog.w(TAG, "StopUserClient failed(), is the HAL stuck? "
+ + "Clearing mStopUserClient");
+ }
+ mStopUserClient = null;
+ }
+ if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
+ mCurrentOperation = null;
+ } else {
+ // can happen if the hal dies and is usually okay
+ // do not unset the current operation that may be newer
+ Slog.w(TAG, "operation is already null or different (reset?): "
+ + mCurrentOperation);
+ }
+ startNextOperationIfIdle();
+ });
+ }
+ }
// Internal callback, notified when an operation is complete. Notifies the requester
// that the operation is complete, before performing internal scheduler work (such as
@@ -164,26 +187,26 @@
private final ClientMonitorCallback mInternalCallback = new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- Slog.d(getTag(), "[Started] " + clientMonitor);
+ Slog.d(TAG, "[Started] " + clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
if (mCurrentOperation == null) {
- Slog.e(getTag(), "[Finishing] " + clientMonitor
+ Slog.e(TAG, "[Finishing] " + clientMonitor
+ " but current operation is null, success: " + success
+ ", possible lifecycle bug in clientMonitor implementation?");
return;
}
if (!mCurrentOperation.isFor(clientMonitor)) {
- Slog.e(getTag(), "[Ignoring Finish] " + clientMonitor + " does not match"
+ Slog.e(TAG, "[Ignoring Finish] " + clientMonitor + " does not match"
+ " current: " + mCurrentOperation);
return;
}
- Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
+ Slog.d(TAG, "[Finishing] " + clientMonitor + ", success: " + success);
if (mGestureAvailabilityDispatcher != null) {
mGestureAvailabilityDispatcher.markSensorActive(
@@ -202,13 +225,11 @@
};
@VisibleForTesting
- public BiometricScheduler(@NonNull String tag,
- @NonNull Handler handler,
+ public BiometricScheduler(@NonNull Handler handler,
@SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull IBiometricService biometricService,
int recentOperationsLimit) {
- mBiometricTag = tag;
mHandler = handler;
mSensorType = sensorType;
mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
@@ -219,49 +240,140 @@
mRecentOperations = new ArrayList<>();
}
+ @VisibleForTesting
+ public BiometricScheduler(@NonNull Handler handler,
+ @SensorType int sensorType,
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull IBiometricService biometricService,
+ int recentOperationsLimit,
+ @NonNull Supplier<Integer> currentUserRetriever,
+ @Nullable UserSwitchProvider<T, U> userSwitchProvider) {
+ mHandler = handler;
+ mSensorType = sensorType;
+ mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
+ mPendingOperations = new ArrayDeque<>();
+ mBiometricService = biometricService;
+ mCrashStates = new ArrayDeque<>();
+ mRecentOperationsLimit = recentOperationsLimit;
+ mRecentOperations = new ArrayList<>();
+ mCurrentUserRetriever = currentUserRetriever;
+ mUserSwitchProvider = userSwitchProvider;
+ }
+
+ public BiometricScheduler(@NonNull Handler handler,
+ @SensorType int sensorType,
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull Supplier<Integer> currentUserRetriever,
+ @NonNull UserSwitchProvider<T, U> userSwitchProvider) {
+ this(handler, sensorType, gestureAvailabilityDispatcher,
+ IBiometricService.Stub.asInterface(ServiceManager.getService(
+ Context.BIOMETRIC_SERVICE)), LOG_NUM_RECENT_OPERATIONS,
+ currentUserRetriever, userSwitchProvider);
+ }
+
/**
* Creates a new scheduler.
*
- * @param tag for the specific instance of the scheduler. Should be unique.
* @param sensorType the sensorType that this scheduler is handling.
* @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures
* (such as fingerprint swipe).
*/
- public BiometricScheduler(@NonNull String tag,
- @SensorType int sensorType,
+ public BiometricScheduler(@SensorType int sensorType,
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
+ this(new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
LOG_NUM_RECENT_OPERATIONS);
}
+ /**
+ * Returns sensor type for a fingerprint sensor.
+ */
+ @SensorType
+ public static int sensorTypeFromFingerprintProperties(
+ @NonNull FingerprintSensorPropertiesInternal props) {
+ if (props.isAnyUdfpsType()) {
+ return SENSOR_TYPE_UDFPS;
+ }
+
+ return SENSOR_TYPE_FP_OTHER;
+ }
+
@VisibleForTesting
public ClientMonitorCallback getInternalCallback() {
return mInternalCallback;
}
- protected String getTag() {
- return BASE_TAG + "/" + mBiometricTag;
+ protected void startNextOperationIfIdle() {
+ if (Flags.deHidl()) {
+ startNextOperation();
+ } else {
+ startNextOperationIfIdleLegacy();
+ }
}
- protected void startNextOperationIfIdle() {
+ protected void startNextOperation() {
if (mCurrentOperation != null) {
- Slog.v(getTag(), "Not idle, current operation: " + mCurrentOperation);
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
return;
}
if (mPendingOperations.isEmpty()) {
- Slog.d(getTag(), "No operations, returning to idle");
+ Slog.d(TAG, "No operations, returning to idle");
+ return;
+ }
+
+ final int currentUserId = mCurrentUserRetriever.get();
+ final int nextUserId = mPendingOperations.getFirst().getTargetUserId();
+
+ if (nextUserId == currentUserId || mPendingOperations.getFirst().isStartUserOperation()) {
+ startNextOperationIfIdleLegacy();
+ } else if (currentUserId == UserHandle.USER_NULL && mUserSwitchProvider != null) {
+ final BaseClientMonitor startClient =
+ mUserSwitchProvider.getStartUserClient(nextUserId);
+ final UserSwitchClientCallback finishedCallback =
+ new UserSwitchClientCallback(startClient);
+
+ Slog.d(TAG, "[Starting User] " + startClient);
+ mCurrentOperation = new BiometricSchedulerOperation(
+ startClient, finishedCallback, STATE_STARTED);
+ startClient.start(finishedCallback);
+ } else if (mUserSwitchProvider != null) {
+ if (mStopUserClient != null) {
+ Slog.d(TAG, "[Waiting for StopUser] " + mStopUserClient);
+ } else {
+ mStopUserClient = mUserSwitchProvider
+ .getStopUserClient(currentUserId);
+ final UserSwitchClientCallback finishedCallback =
+ new UserSwitchClientCallback(mStopUserClient);
+
+ Slog.d(TAG, "[Stopping User] current: " + currentUserId
+ + ", next: " + nextUserId + ". " + mStopUserClient);
+ mCurrentOperation = new BiometricSchedulerOperation(
+ mStopUserClient, finishedCallback, STATE_STARTED);
+ mStopUserClient.start(finishedCallback);
+ }
+ } else {
+ Slog.e(TAG, "Cannot start next operation.");
+ }
+ }
+
+ protected void startNextOperationIfIdleLegacy() {
+ if (mCurrentOperation != null) {
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
+ return;
+ }
+ if (mPendingOperations.isEmpty()) {
+ Slog.d(TAG, "No operations, returning to idle");
return;
}
mCurrentOperation = mPendingOperations.poll();
- Slog.d(getTag(), "[Polled] " + mCurrentOperation);
+ Slog.d(TAG, "[Polled] " + mCurrentOperation);
// If the operation at the front of the queue has been marked for cancellation, send
// ERROR_CANCELED. No need to start this client.
if (mCurrentOperation.isMarkedCanceling()) {
- Slog.d(getTag(), "[Now Cancelling] " + mCurrentOperation);
+ Slog.d(TAG, "[Now Cancelling] " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
// Now we wait for the client to send its FinishCallback, which kicks off the next
// operation.
@@ -289,7 +401,7 @@
// Note down current length of queue
final int pendingOperationsLength = mPendingOperations.size();
final BiometricSchedulerOperation lastOperation = mPendingOperations.peekLast();
- Slog.e(getTag(), "[Unable To Start] " + mCurrentOperation
+ Slog.e(TAG, "[Unable To Start] " + mCurrentOperation
+ ". Last pending operation: " + lastOperation);
// Then for each operation currently in the pending queue at the time of this
@@ -298,10 +410,10 @@
for (int i = 0; i < pendingOperationsLength; i++) {
final BiometricSchedulerOperation operation = mPendingOperations.pollFirst();
if (operation != null) {
- Slog.w(getTag(), "[Aborting Operation] " + operation);
+ Slog.w(TAG, "[Aborting Operation] " + operation);
operation.abort();
} else {
- Slog.e(getTag(), "Null operation, index: " + i
+ Slog.e(TAG, "Null operation, index: " + i
+ ", expected length: " + pendingOperationsLength);
}
}
@@ -317,9 +429,9 @@
mBiometricService.onReadyForAuthentication(
mCurrentOperation.getClientMonitor().getRequestId(), cookie);
} catch (RemoteException e) {
- Slog.e(getTag(), "Remote exception when contacting BiometricService", e);
+ Slog.e(TAG, "Remote exception when contacting BiometricService", e);
}
- Slog.d(getTag(), "Waiting for cookie before starting: " + mCurrentOperation);
+ Slog.d(TAG, "Waiting for cookie before starting: " + mCurrentOperation);
}
}
@@ -338,14 +450,14 @@
*/
public void startPreparedClient(int cookie) {
if (mCurrentOperation == null) {
- Slog.e(getTag(), "Current operation is null");
+ Slog.e(TAG, "Current operation is null");
return;
}
if (mCurrentOperation.startWithCookie(mInternalCallback, cookie)) {
- Slog.d(getTag(), "[Started] Prepared client: " + mCurrentOperation);
+ Slog.d(TAG, "[Started] Prepared client: " + mCurrentOperation);
} else {
- Slog.e(getTag(), "[Unable To Start] Prepared client: " + mCurrentOperation);
+ Slog.e(TAG, "[Unable To Start] Prepared client: " + mCurrentOperation);
mCurrentOperation = null;
startNextOperationIfIdle();
}
@@ -374,13 +486,13 @@
if (clientMonitor.interruptsPrecedingClients()) {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (operation.markCanceling()) {
- Slog.d(getTag(), "New client, marking pending op as canceling: " + operation);
+ Slog.d(TAG, "New client, marking pending op as canceling: " + operation);
}
}
}
mPendingOperations.add(new BiometricSchedulerOperation(clientMonitor, clientCallback));
- Slog.d(getTag(), "[Added] " + clientMonitor
+ Slog.d(TAG, "[Added] " + clientMonitor
+ ", new queue size: " + mPendingOperations.size());
// If the new operation should interrupt preceding clients, and if the current operation is
@@ -389,7 +501,7 @@
&& mCurrentOperation != null
&& mCurrentOperation.isInterruptable()
&& mCurrentOperation.isStarted()) {
- Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
+ Slog.d(TAG, "[Cancelling Interruptable]: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
startNextOperationIfIdle();
@@ -401,16 +513,16 @@
* @param token from the caller, should match the token passed in when requesting enrollment
*/
public void cancelEnrollment(IBinder token, long requestId) {
- Slog.d(getTag(), "cancelEnrollment, requestId: " + requestId);
+ Slog.d(TAG, "cancelEnrollment, requestId: " + requestId);
if (mCurrentOperation != null
&& canCancelEnrollOperation(mCurrentOperation, token, requestId)) {
- Slog.d(getTag(), "Cancelling enrollment op: " + mCurrentOperation);
+ Slog.d(TAG, "Cancelling enrollment op: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (canCancelEnrollOperation(operation, token, requestId)) {
- Slog.d(getTag(), "Cancelling pending enrollment op: " + operation);
+ Slog.d(TAG, "Cancelling pending enrollment op: " + operation);
operation.markCanceling();
}
}
@@ -423,16 +535,16 @@
* @param requestId the id returned when requesting authentication
*/
public void cancelAuthenticationOrDetection(IBinder token, long requestId) {
- Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId);
+ Slog.d(TAG, "cancelAuthenticationOrDetection, requestId: " + requestId);
if (mCurrentOperation != null
&& canCancelAuthOperation(mCurrentOperation, token, requestId)) {
- Slog.d(getTag(), "Cancelling auth/detect op: " + mCurrentOperation);
+ Slog.d(TAG, "Cancelling auth/detect op: " + mCurrentOperation);
mCurrentOperation.cancel(mHandler, mInternalCallback);
} else {
for (BiometricSchedulerOperation operation : mPendingOperations) {
if (canCancelAuthOperation(operation, token, requestId)) {
- Slog.d(getTag(), "Cancelling pending auth/detect op: " + operation);
+ Slog.d(TAG, "Cancelling pending auth/detect op: " + operation);
operation.markCanceling();
}
}
@@ -504,11 +616,11 @@
mCurrentOperation != null ? mCurrentOperation.toString() : null,
pendingOperations);
mCrashStates.add(crashState);
- Slog.e(getTag(), "Recorded crash state: " + crashState.toString());
+ Slog.e(TAG, "Recorded crash state: " + crashState.toString());
}
public void dump(PrintWriter pw) {
- pw.println("Dump of BiometricScheduler " + getTag());
+ pw.println("Dump of BiometricScheduler " + TAG);
pw.println("Type: " + mSensorType);
pw.println("Current operation: " + mCurrentOperation);
pw.println("Pending operations: " + mPendingOperations.size());
@@ -548,7 +660,7 @@
* HAL dies.
*/
public void reset() {
- Slog.d(getTag(), "Resetting scheduler");
+ Slog.d(TAG, "Resetting scheduler");
mPendingOperations.clear();
mCurrentOperation = null;
}
@@ -562,11 +674,11 @@
return;
}
for (BiometricSchedulerOperation pendingOperation : mPendingOperations) {
- Slog.d(getTag(), "[Watchdog cancelling pending] "
+ Slog.d(TAG, "[Watchdog cancelling pending] "
+ pendingOperation.getClientMonitor());
pendingOperation.markCancelingForWatchdog();
}
- Slog.d(getTag(), "[Watchdog cancelling current] "
+ Slog.d(TAG, "[Watchdog cancelling current] "
+ mCurrentOperation.getClientMonitor());
mCurrentOperation.cancel(mHandler, getInternalCallback());
}
@@ -590,9 +702,23 @@
/**
* Handle stop user client when user switching occurs.
*/
- public void onUserStopped() {}
+ public void onUserStopped() {
+ if (mStopUserClient == null) {
+ Slog.e(TAG, "Unexpected onUserStopped");
+ return;
+ }
+
+ Slog.d(TAG, "[OnUserStopped]: " + mStopUserClient);
+ mStopUserClient.onUserStopped();
+ mStopUserClient = null;
+ }
public Handler getHandler() {
return mHandler;
}
+
+ @Nullable
+ public StopUserClient<?> getStopUserClient() {
+ return mStopUserClient;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
index e8654dc..e01c4ec 100644
--- a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java
@@ -30,7 +30,10 @@
/**
* Abstract class for stopping a user.
- * @param <T> Interface for stopping the user.
+ *
+ * @param <T> Session for stopping the user. It should be either an instance of
+ * {@link com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession} or
+ * {@link com.android.server.biometrics.sensors.face.aidl.AidlSession}.
*/
public abstract class StopUserClient<T> extends HalClientMonitor<T> {
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index 3753bbd..7ca10e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -33,10 +33,14 @@
/**
* A user-aware scheduler that requests user-switches based on scheduled operation's targetUserId.
+ * TODO (b/304604965): Remove class when Flags.FLAG_DE_HIDL is removed.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
*/
-public class UserAwareBiometricScheduler extends BiometricScheduler {
+public class UserAwareBiometricScheduler<T, U> extends BiometricScheduler<T, U> {
- private static final String BASE_TAG = "UaBiometricScheduler";
+ private static final String TAG = "UaBiometricScheduler";
/**
* Interface to retrieve the owner's notion of the current userId. Note that even though
@@ -66,13 +70,13 @@
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
- Slog.d(getTag(), "[Client finished] " + clientMonitor + ", success: " + success);
+ Slog.d(TAG, "[Client finished] " + clientMonitor + ", success: " + success);
// Set mStopUserClient to null when StopUserClient fails. Otherwise it's possible
// for that the queue will wait indefinitely until the field is cleared.
if (clientMonitor instanceof StopUserClient<?>) {
if (!success) {
- Slog.w(getTag(), "StopUserClient failed(), is the HAL stuck? "
+ Slog.w(TAG, "StopUserClient failed(), is the HAL stuck? "
+ "Clearing mStopUserClient");
}
mStopUserClient = null;
@@ -82,7 +86,7 @@
} else {
// can happen if the hal dies and is usually okay
// do not unset the current operation that may be newer
- Slog.w(getTag(), "operation is already null or different (reset?): "
+ Slog.w(TAG, "operation is already null or different (reset?): "
+ mCurrentOperation);
}
startNextOperationIfIdle();
@@ -98,7 +102,7 @@
@NonNull IBiometricService biometricService,
@NonNull CurrentUserRetriever currentUserRetriever,
@NonNull UserSwitchCallback userSwitchCallback) {
- super(tag, handler, sensorType, gestureAvailabilityDispatcher, biometricService,
+ super(handler, sensorType, gestureAvailabilityDispatcher, biometricService,
LOG_NUM_RECENT_OPERATIONS);
mCurrentUserRetriever = currentUserRetriever;
@@ -117,18 +121,13 @@
}
@Override
- protected String getTag() {
- return BASE_TAG + "/" + mBiometricTag;
- }
-
- @Override
protected void startNextOperationIfIdle() {
if (mCurrentOperation != null) {
- Slog.v(getTag(), "Not idle, current operation: " + mCurrentOperation);
+ Slog.v(TAG, "Not idle, current operation: " + mCurrentOperation);
return;
}
if (mPendingOperations.isEmpty()) {
- Slog.d(getTag(), "No operations, returning to idle");
+ Slog.d(TAG, "No operations, returning to idle");
return;
}
@@ -143,20 +142,20 @@
final ClientFinishedCallback finishedCallback =
new ClientFinishedCallback(startClient);
- Slog.d(getTag(), "[Starting User] " + startClient);
+ Slog.d(TAG, "[Starting User] " + startClient);
mCurrentOperation = new BiometricSchedulerOperation(
startClient, finishedCallback, STATE_STARTED);
startClient.start(finishedCallback);
} else {
if (mStopUserClient != null) {
- Slog.d(getTag(), "[Waiting for StopUser] " + mStopUserClient);
+ Slog.d(TAG, "[Waiting for StopUser] " + mStopUserClient);
} else {
mStopUserClient = mUserSwitchCallback
.getStopUserClient(currentUserId);
final ClientFinishedCallback finishedCallback =
new ClientFinishedCallback(mStopUserClient);
- Slog.d(getTag(), "[Stopping User] current: " + currentUserId
+ Slog.d(TAG, "[Stopping User] current: " + currentUserId
+ ", next: " + nextUserId + ". " + mStopUserClient);
mCurrentOperation = new BiometricSchedulerOperation(
mStopUserClient, finishedCallback, STATE_STARTED);
@@ -168,11 +167,11 @@
@Override
public void onUserStopped() {
if (mStopUserClient == null) {
- Slog.e(getTag(), "Unexpected onUserStopped");
+ Slog.e(TAG, "Unexpected onUserStopped");
return;
}
- Slog.d(getTag(), "[OnUserStopped]: " + mStopUserClient);
+ Slog.d(TAG, "[OnUserStopped]: " + mStopUserClient);
mStopUserClient.onUserStopped();
mStopUserClient = null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java b/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java
new file mode 100644
index 0000000..bc5c55b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/UserSwitchProvider.java
@@ -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.server.biometrics.sensors;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface to get the appropriate start and stop user clients.
+ *
+ * @param <T> Hal instance for starting the user.
+ * @param <U> Session associated with the current user id.
+ */
+public interface UserSwitchProvider<T, U> {
+ @NonNull
+ StartUserClient<T, U> getStartUserClient(int newUserId);
+ @NonNull
+ StopUserClient<U> getStopUserClient(int userId);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
index af46f44..3d61f99 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/AidlSession.java
@@ -53,12 +53,10 @@
mAidlResponseHandler = aidlResponseHandler;
}
- /** The underlying {@link ISession}. */
@NonNull public ISession getSession() {
return mSession;
}
- /** The user id associated with the session. */
public int getUserId() {
return mUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 9fa15b8..e4ecf1a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -39,6 +39,7 @@
import android.hardware.face.IFaceServiceReceiver;
import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -88,6 +89,8 @@
* Provider for a single instance of the {@link IFace} HAL.
*/
public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
+
+ private static final String TAG = "FaceProvider";
private static final int ENROLL_TIMEOUT_SEC = 75;
private boolean mTestHalEnabled;
@@ -159,7 +162,7 @@
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge) {
this(context, biometricStateCallback, props, halInstanceName, lockoutResetDispatcher,
- biometricContext, null /* daemon */, resetLockoutRequiresChallenge,
+ biometricContext, null /* daemon */, getHandler(), resetLockoutRequiresChallenge,
false /* testHalEnabled */);
}
@@ -169,13 +172,19 @@
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricContext biometricContext,
- @Nullable IFace daemon, boolean resetLockoutRequiresChallenge,
+ @Nullable IFace daemon,
+ @NonNull Handler handler,
+ boolean resetLockoutRequiresChallenge,
boolean testHalEnabled) {
mContext = context;
mBiometricStateCallback = biometricStateCallback;
mHalInstanceName = halInstanceName;
mFaceSensors = new SensorList<>(ActivityManager.getService());
- mHandler = new Handler(Looper.getMainLooper());
+ if (Flags.deHidl()) {
+ mHandler = handler;
+ } else {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
mUsageStats = new UsageStats(context);
mLockoutResetDispatcher = lockoutResetDispatcher;
mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -189,6 +198,13 @@
initSensors(resetLockoutRequiresChallenge, props);
}
+ @NonNull
+ private static Handler getHandler() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return new Handler(handlerThread.getLooper());
+ }
+
private void initAuthenticationBroadcastReceiver() {
new AuthenticationStatsBroadcastReceiver(
mContext,
@@ -230,8 +246,8 @@
prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
prop.supportsDetectInteraction, prop.halControlsPreview,
false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this,
- mContext, mHandler, internalProp, mLockoutResetDispatcher,
+ final Sensor sensor = new Sensor(this,
+ mContext, mHandler, internalProp,
mBiometricContext);
sensor.init(mLockoutResetDispatcher, this);
final int userId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
@@ -250,9 +266,8 @@
private void addHidlSensors(SensorProps prop, boolean resetLockoutRequiresChallenge) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new HidlToAidlSensorAdapter(getTag() + "/" + sensorId, this,
- mContext, mHandler, prop, mLockoutResetDispatcher,
- mBiometricContext, resetLockoutRequiresChallenge,
+ final Sensor sensor = new HidlToAidlSensorAdapter(this, mContext, mHandler, prop,
+ mLockoutResetDispatcher, mBiometricContext, resetLockoutRequiresChallenge,
() -> {
//TODO: update to make this testable
scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
@@ -279,8 +294,7 @@
private void addAidlSensors(SensorProps prop, boolean resetLockoutRequiresChallenge) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext,
- mHandler, prop, mLockoutResetDispatcher, mBiometricContext,
+ final Sensor sensor = new Sensor(this, mContext, mHandler, prop, mBiometricContext,
resetLockoutRequiresChallenge);
sensor.init(mLockoutResetDispatcher, this);
final int userId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
@@ -296,7 +310,7 @@
}
private String getTag() {
- return "FaceProvider/" + mHalInstanceName;
+ return TAG + "/" + mHalInstanceName;
}
boolean hasHalInstance() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
index 0110ae9..e5ae8e3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceStopUserClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.face.ISession;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -30,10 +31,10 @@
import java.util.function.Supplier;
-public class FaceStopUserClient extends StopUserClient<AidlSession> {
+public class FaceStopUserClient extends StopUserClient<ISession> {
private static final String TAG = "FaceStopUserClient";
- public FaceStopUserClient(@NonNull Context context, @NonNull Supplier<AidlSession> lazyDaemon,
+ public FaceStopUserClient(@NonNull Context context, @NonNull Supplier<ISession> lazyDaemon,
@Nullable IBinder token, int userId, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStoppedCallback callback) {
@@ -49,7 +50,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().getSession().close();
+ getFreshDaemon().close();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
getCallback().onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 3e5c599..635e79a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -58,6 +58,7 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.face.FaceUtils;
import java.util.ArrayList;
@@ -71,15 +72,16 @@
*/
public class Sensor {
+ private static final String TAG = "Sensor";
+
private boolean mTestHalEnabled;
- @NonNull private final String mTag;
@NonNull private final FaceProvider mProvider;
@NonNull private final Context mContext;
@NonNull private final IBinder mToken;
@NonNull private final Handler mHandler;
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
- @NonNull private BiometricScheduler mScheduler;
+ @NonNull private BiometricScheduler<IFace, ISession> mScheduler;
@Nullable private LockoutTracker mLockoutTracker;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@@ -88,11 +90,9 @@
@NonNull BiometricContext mBiometricContext;
- Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ Sensor(@NonNull FaceProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext, @Nullable AidlSession session) {
- mTag = tag;
+ @NonNull BiometricContext biometricContext) {
mProvider = provider;
mContext = context;
mToken = new Binder();
@@ -102,105 +102,135 @@
mAuthenticatorIds = new HashMap<>();
}
- Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
- @NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext) {
- this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
- biometricContext, null);
- }
-
- public Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ public Sensor(@NonNull FaceProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull SensorProps prop,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge) {
- this(tag, provider, context, handler,
+ this(provider, context, handler,
getFaceSensorPropertiesInternal(prop, resetLockoutRequiresChallenge),
- lockoutResetDispatcher, biometricContext, null);
+ biometricContext);
}
/**
* Initialize biometric scheduler, lockout tracker and session for the sensor.
*/
- public void init(LockoutResetDispatcher lockoutResetDispatcher,
+ public void init(@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ if (Flags.deHidl()) {
+ setScheduler(getBiometricSchedulerForInit(lockoutResetDispatcher, provider));
+ } else {
+ setScheduler(getUserAwareBiometricSchedulerForInit(lockoutResetDispatcher, provider));
+ }
+ mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ mLockoutTracker = new LockoutCache();
+ }
+
+ private BiometricScheduler<IFace, ISession> getBiometricSchedulerForInit(
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ return new BiometricScheduler<>(mHandler,
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ () -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
+ new UserSwitchProvider<IFace, ISession>() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FaceStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken, userId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext),
+ mBiometricContext, () -> mCurrentSession = null);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFace, ISession> getStartUserClient(int newUserId) {
+ final int sensorId = mSensorProperties.sensorId;
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ },
+ new AidlResponseHandler.AidlResponseHandlerCallback() {
+ @Override
+ public void onEnrollSuccess() {
+ mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
+ newUserId);
+ mProvider.scheduleInvalidationRequest(sensorId,
+ newUserId);
+ }
+
+ @Override
+ public void onHardwareUnavailable() {
+ Slog.e(TAG, "Face sensor hardware unavailable.");
+ mCurrentSession = null;
+ }
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId, provider);
+ }
+ });
+ }
+
+ private UserAwareBiometricScheduler<IFace, ISession> getUserAwareBiometricSchedulerForInit(
+ LockoutResetDispatcher lockoutResetDispatcher,
FaceProvider provider) {
- mScheduler = new UserAwareBiometricScheduler(mTag,
+ return new UserAwareBiometricScheduler<>(TAG,
BiometricScheduler.SENSOR_TYPE_FACE, null /* gestureAvailabilityDispatcher */,
() -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new FaceStopUserClient(mContext, mLazySession, mToken, userId,
- mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- () -> mCurrentSession = null);
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FaceStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken, userId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext),
+ mBiometricContext, () -> mCurrentSession = null);
}
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<IFace, ISession> getStartUserClient(int newUserId) {
final int sensorId = mSensorProperties.sensorId;
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ Slog.e(TAG, "Face sensor hardware unavailable.");
+ mCurrentSession = null;
+ });
- final AidlResponseHandler resultController;
- if (Flags.deHidl()) {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {},
- new AidlResponseHandler.AidlResponseHandlerCallback() {
- @Override
- public void onEnrollSuccess() {
- mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
- newUserId);
- mProvider.scheduleInvalidationRequest(sensorId,
- newUserId);
- }
-
- @Override
- public void onHardwareUnavailable() {
- Slog.e(mTag, "Face sensor hardware unavailable.");
- mCurrentSession = null;
- }
- });
- } else {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {
- Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
- mCurrentSession = null;
- });
- }
-
- final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
- (userIdStarted, newSession, halInterfaceVersion) -> {
- Slog.d(mTag, "New session created for user: "
- + userIdStarted + " with hal version: "
- + halInterfaceVersion);
- mCurrentSession = new AidlSession(halInterfaceVersion,
- newSession, userIdStarted, resultController);
- if (FaceUtils.getLegacyInstance(sensorId)
- .isInvalidationInProgress(mContext, userIdStarted)) {
- Slog.w(mTag,
- "Scheduling unfinished invalidation request for "
- + "sensor: "
- + sensorId
- + ", user: " + userIdStarted);
- provider.scheduleInvalidationRequest(sensorId,
- userIdStarted);
- }
- };
-
- return new FaceStartUserClient(mContext, provider::getHalInstance,
- mToken, newUserId, mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- resultController, userStartedCallback);
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId, provider);
}
});
- mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
- mLockoutTracker = new LockoutCache();
+ }
+
+ private FaceStartUserClient getStartUserClient(@NonNull AidlResponseHandler resultController,
+ int sensorId, int newUserId, @NonNull FaceProvider provider) {
+ final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
+ (userIdStarted, newSession, halInterfaceVersion) -> {
+ Slog.d(TAG, "New face session created for user: "
+ + userIdStarted + " with hal version: "
+ + halInterfaceVersion);
+ mCurrentSession = new AidlSession(halInterfaceVersion,
+ newSession, userIdStarted, resultController);
+ if (FaceUtils.getLegacyInstance(sensorId)
+ .isInvalidationInProgress(mContext, userIdStarted)) {
+ Slog.w(TAG,
+ "Scheduling unfinished invalidation request for "
+ + "face sensor: "
+ + sensorId
+ + ", user: " + userIdStarted);
+ provider.scheduleInvalidationRequest(sensorId,
+ userIdStarted);
+ }
+ };
+
+ return new FaceStartUserClient(mContext, provider::getHalInstance, mToken, newUserId,
+ mSensorProperties.sensorId, BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ resultController, userStartedCallback);
}
private static FaceSensorPropertiesInternal getFaceSensorPropertiesInternal(SensorProps prop,
@@ -213,13 +243,11 @@
info.softwareVersion));
}
}
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ return new FaceSensorPropertiesInternal(
prop.commonProps.sensorId, prop.commonProps.sensorStrength,
prop.commonProps.maxEnrollmentsPerUser, componentInfo, prop.sensorType,
prop.supportsDetectInteraction, prop.halControlsPreview,
resetLockoutRequiresChallenge);
-
- return internalProp;
}
@NonNull public Supplier<AidlSession> getLazySession() {
@@ -243,7 +271,7 @@
mProvider, this);
}
- @NonNull public BiometricScheduler getScheduler() {
+ @NonNull public BiometricScheduler<IFace, ISession> getScheduler() {
return mScheduler;
}
@@ -259,17 +287,17 @@
}
void setTestHalEnabled(boolean enabled) {
- Slog.w(mTag, "setTestHalEnabled: " + enabled);
+ Slog.w(TAG, "Face setTestHalEnabled: " + enabled);
if (enabled != mTestHalEnabled) {
// The framework should retrieve a new session from the HAL.
try {
if (mCurrentSession != null) {
// TODO(181984005): This should be scheduled instead of directly invoked
- Slog.d(mTag, "Closing old session");
+ Slog.d(TAG, "Closing old face session");
mCurrentSession.getSession().close();
}
} catch (RemoteException e) {
- Slog.e(mTag, "RemoteException", e);
+ Slog.e(TAG, "RemoteException", e);
}
mCurrentSession = null;
}
@@ -308,7 +336,7 @@
public void onBinderDied() {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (client != null && client.isInterruptable()) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ Slog.e(TAG, "Sending face hardware unavailable error for client: " + client);
final ErrorConsumer errorConsumer = (ErrorConsumer) client;
errorConsumer.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 46ce0b6..5337666 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -120,7 +120,7 @@
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
@NonNull private final BiometricStateCallback mBiometricStateCallback;
@NonNull private final Context mContext;
- @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final BiometricScheduler<IBiometricsFace, AidlSession> mScheduler;
@NonNull private final Handler mHandler;
@NonNull private final Supplier<IBiometricsFace> mLazyDaemon;
@NonNull private final LockoutHalImpl mLockoutTracker;
@@ -163,14 +163,15 @@
private final int mSensorId;
@NonNull private final Context mContext;
@NonNull private final Handler mHandler;
- @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final BiometricScheduler<IBiometricsFace, AidlSession> mScheduler;
@Nullable private Callback mCallback;
@NonNull private final LockoutHalImpl mLockoutTracker;
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
- @NonNull BiometricScheduler scheduler, @NonNull LockoutHalImpl lockoutTracker,
+ @NonNull BiometricScheduler<IBiometricsFace, AidlSession> scheduler,
+ @NonNull LockoutHalImpl lockoutTracker,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
mSensorId = sensorId;
mContext = context;
@@ -352,7 +353,7 @@
@NonNull FaceSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull Handler handler,
- @NonNull BiometricScheduler scheduler,
+ @NonNull BiometricScheduler<IBiometricsFace, AidlSession> scheduler,
@NonNull BiometricContext biometricContext) {
mSensorProperties = sensorProps;
mContext = context;
@@ -395,7 +396,8 @@
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
final Handler handler = new Handler(Looper.getMainLooper());
return new Face10(context, biometricStateCallback, sensorProps, lockoutResetDispatcher,
- handler, new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE,
+ handler, new BiometricScheduler<>(
+ BiometricScheduler.SENSOR_TYPE_FACE,
null /* gestureAvailabilityTracker */),
BiometricContext.getInstance(context));
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
index 6355cb5..a004cae4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.biometrics.face.V1_0.IBiometricsFace;
import android.os.Handler;
@@ -67,8 +68,7 @@
};
private LockoutHalImpl mLockoutTracker;
- public HidlToAidlSensorAdapter(@NonNull String tag,
- @NonNull FaceProvider provider,
+ public HidlToAidlSensorAdapter(@NonNull FaceProvider provider,
@NonNull Context context,
@NonNull Handler handler,
@NonNull SensorProps prop,
@@ -76,15 +76,14 @@
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresChallenge,
@NonNull Runnable internalCleanupAndGetFeatureRunnable) {
- this(tag, provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
+ this(provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
resetLockoutRequiresChallenge, internalCleanupAndGetFeatureRunnable,
new AuthSessionCoordinator(), null /* daemon */,
null /* onEnrollSuccessCallback */);
}
@VisibleForTesting
- HidlToAidlSensorAdapter(@NonNull String tag,
- @NonNull FaceProvider provider,
+ HidlToAidlSensorAdapter(@NonNull FaceProvider provider,
@NonNull Context context,
@NonNull Handler handler,
@NonNull SensorProps prop,
@@ -95,7 +94,7 @@
@NonNull AuthSessionCoordinator authSessionCoordinator,
@Nullable IBiometricsFace daemon,
@Nullable AidlResponseHandler.AidlResponseHandlerCallback aidlResponseHandlerCallback) {
- super(tag, provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
+ super(provider, context, handler, prop, biometricContext,
resetLockoutRequiresChallenge);
mInternalCleanupAndGetFeatureRunnable = internalCleanupAndGetFeatureRunnable;
mFaceProvider = provider;
@@ -124,7 +123,7 @@
@Override
public void serviceDied(long cookie) {
- Slog.d(TAG, "HAL died.");
+ Slog.d(TAG, "Face HAL died.");
mDaemon = null;
}
@@ -140,10 +139,12 @@
}
@Override
- public void init(LockoutResetDispatcher lockoutResetDispatcher,
- FaceProvider provider) {
- setScheduler(new BiometricScheduler(TAG, BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityTracker */));
+ public void init(@NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull FaceProvider provider) {
+ setScheduler(new BiometricScheduler<ISession, AidlSession>(getHandler(),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityTracker */, () -> mCurrentUserId,
+ null /* userSwitchProvider */));
setLazySession(this::getSession);
mLockoutTracker = new LockoutHalImpl();
}
@@ -188,7 +189,7 @@
return mDaemon;
}
- Slog.d(TAG, "Daemon was null, reconnecting, current operation: "
+ Slog.d(TAG, "Face daemon was null, reconnecting, current operation: "
+ getScheduler().getCurrentClient());
try {
@@ -213,7 +214,7 @@
}
@VisibleForTesting void handleUserChanged(int newUserId) {
- Slog.d(TAG, "User changed. Current user is " + newUserId);
+ Slog.d(TAG, "User changed. Current user for face sensor is " + newUserId);
mSession = null;
mCurrentUserId = newUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
index 5daf2d4..fa95361 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSessionAdapter.java
@@ -282,7 +282,7 @@
@Override
public ICancellationSignal enrollWithOptions(FaceEnrollOptions options) {
- //Unsupported in HIDL
+ Slog.e(TAG, "enrollWithOptions unsupported in HIDL");
return null;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
index 8ff105b..0d4dac0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlSession.java
@@ -51,12 +51,10 @@
mAidlResponseHandler = aidlResponseHandler;
}
- /** The underlying {@link ISession}. */
@NonNull public ISession getSession() {
return mSession;
}
- /** The user id associated with the session. */
public int getUserId() {
return mUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 88a11d9..c0388d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -46,6 +46,7 @@
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
@@ -102,6 +103,8 @@
@SuppressWarnings("deprecation")
public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvider {
+ private static final String TAG = "FingerprintProvider";
+
private boolean mTestHalEnabled;
@NonNull
@@ -172,7 +175,7 @@
boolean resetLockoutRequiresHardwareAuthToken) {
this(context, biometricStateCallback, authenticationStateListeners, props, halInstanceName,
lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext,
- null /* daemon */, resetLockoutRequiresHardwareAuthToken,
+ null /* daemon */, getHandler(), resetLockoutRequiresHardwareAuthToken,
false /* testHalEnabled */);
}
@@ -184,6 +187,7 @@
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
@Nullable IFingerprint daemon,
+ @NonNull Handler handler,
boolean resetLockoutRequiresHardwareAuthToken,
boolean testHalEnabled) {
mContext = context;
@@ -191,7 +195,11 @@
mAuthenticationStateListeners = authenticationStateListeners;
mHalInstanceName = halInstanceName;
mFingerprintSensors = new SensorList<>(ActivityManager.getService());
- mHandler = new Handler(Looper.getMainLooper());
+ if (Flags.deHidl()) {
+ mHandler = handler;
+ } else {
+ mHandler = new Handler(Looper.getMainLooper());
+ }
mLockoutResetDispatcher = lockoutResetDispatcher;
mActivityTaskManager = ActivityTaskManager.getInstance();
mTaskStackListener = new BiometricTaskStackListener();
@@ -204,6 +212,13 @@
initSensors(resetLockoutRequiresHardwareAuthToken, props, gestureAvailabilityDispatcher);
}
+ @NonNull
+ private static Handler getHandler() {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ return new Handler(handlerThread.getLooper());
+ }
+
private void initAuthenticationBroadcastReceiver() {
new AuthenticationStatsBroadcastReceiver(
mContext,
@@ -262,11 +277,9 @@
location.sensorLocationY,
location.sensorRadius))
.collect(Collectors.toList()));
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext,
- mHandler, internalProp, mLockoutResetDispatcher,
- gestureAvailabilityDispatcher, mBiometricContext);
- sensor.init(gestureAvailabilityDispatcher,
- mLockoutResetDispatcher);
+ final Sensor sensor = new Sensor(this, mContext, mHandler, internalProp,
+ mBiometricContext);
+ sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
final int sessionUserId =
sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
sensor.getLazySession().get().getUserId();
@@ -286,10 +299,8 @@
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
boolean resetLockoutRequiresHardwareAuthToken) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new HidlToAidlSensorAdapter(getTag() + "/"
- + sensorId, this, mContext, mHandler,
- prop, mLockoutResetDispatcher, gestureAvailabilityDispatcher,
- mBiometricContext, resetLockoutRequiresHardwareAuthToken,
+ final Sensor sensor = new HidlToAidlSensorAdapter(this, mContext, mHandler, prop,
+ mLockoutResetDispatcher, mBiometricContext, resetLockoutRequiresHardwareAuthToken,
() -> scheduleInternalCleanup(sensorId, ActivityManager.getCurrentUser(),
null /* callback */));
sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
@@ -307,14 +318,11 @@
private void addAidlSensors(@NonNull SensorProps prop,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- List<SensorLocationInternal> workaroundLocations,
+ @NonNull List<SensorLocationInternal> workaroundLocations,
boolean resetLockoutRequiresHardwareAuthToken) {
final int sensorId = prop.commonProps.sensorId;
- final Sensor sensor = new Sensor(getTag() + "/" + sensorId,
- this, mContext, mHandler,
- prop, mLockoutResetDispatcher, gestureAvailabilityDispatcher,
- mBiometricContext, workaroundLocations,
- resetLockoutRequiresHardwareAuthToken);
+ final Sensor sensor = new Sensor(this, mContext, mHandler, prop, mBiometricContext,
+ workaroundLocations, resetLockoutRequiresHardwareAuthToken);
sensor.init(gestureAvailabilityDispatcher, mLockoutResetDispatcher);
final int sessionUserId = sensor.getLazySession().get() == null ? UserHandle.USER_NULL :
sensor.getLazySession().get().getUserId();
@@ -329,7 +337,7 @@
}
private String getTag() {
- return "FingerprintProvider/" + mHalInstanceName;
+ return TAG + "/" + mHalInstanceName;
}
boolean hasHalInstance() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
index 2cc1879..394f045 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.fingerprint.ISession;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -30,11 +31,11 @@
import java.util.function.Supplier;
-public class FingerprintStopUserClient extends StopUserClient<AidlSession> {
+public class FingerprintStopUserClient extends StopUserClient<ISession> {
private static final String TAG = "FingerprintStopUserClient";
public FingerprintStopUserClient(@NonNull Context context,
- @NonNull Supplier<AidlSession> lazyDaemon, @Nullable IBinder token, int userId,
+ @NonNull Supplier<ISession> lazyDaemon, @Nullable IBinder token, int userId,
int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull UserStoppedCallback callback) {
@@ -50,7 +51,7 @@
@Override
protected void startHalOperation() {
try {
- getFreshDaemon().getSession().close();
+ getFreshDaemon().close();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
getCallback().onClientFinished(this, false /* success */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index dd887bb..af88c62 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -59,6 +59,7 @@
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
@@ -77,15 +78,16 @@
@SuppressWarnings("deprecation")
public class Sensor {
+ private static final String TAG = "Sensor";
+
private boolean mTestHalEnabled;
- @NonNull private final String mTag;
@NonNull private final FingerprintProvider mProvider;
@NonNull private final Context mContext;
@NonNull private final IBinder mToken;
@NonNull private final Handler mHandler;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
- @NonNull private BiometricScheduler mScheduler;
+ @NonNull private BiometricScheduler<IFingerprint, ISession> mScheduler;
@NonNull private LockoutTracker mLockoutTracker;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@NonNull private final BiometricContext mBiometricContext;
@@ -93,13 +95,10 @@
@Nullable AidlSession mCurrentSession;
@NonNull private Supplier<AidlSession> mLazySession;
- public Sensor(@NonNull String tag, @NonNull FingerprintProvider provider,
+ public Sensor(@NonNull FingerprintProvider provider,
@NonNull Context context, @NonNull Handler handler,
@NonNull FingerprintSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext, AidlSession session) {
- mTag = tag;
mProvider = provider;
mContext = context;
mToken = new Binder();
@@ -110,41 +109,52 @@
mCurrentSession = session;
}
- Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
+ Sensor(@NonNull FingerprintProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext) {
- this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext, null);
+ this(provider, context, handler, sensorProperties,
+ biometricContext, null);
}
- Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
+ Sensor(@NonNull FingerprintProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull SensorProps sensorProp,
- @NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
@NonNull List<SensorLocationInternal> workaroundLocation,
boolean resetLockoutRequiresHardwareAuthToken) {
- this(tag, provider, context, handler, getFingerprintSensorPropertiesInternal(sensorProp,
+ this(provider, context, handler, getFingerprintSensorPropertiesInternal(sensorProp,
workaroundLocation, resetLockoutRequiresHardwareAuthToken),
- lockoutResetDispatcher, gestureAvailabilityDispatcher, biometricContext, null);
+ biometricContext, null);
}
/**
* Initialize biometric scheduler, lockout tracker and session for the sensor.
*/
- public void init(GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- LockoutResetDispatcher lockoutResetDispatcher) {
- mScheduler = new UserAwareBiometricScheduler(mTag,
+ public void init(@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ if (Flags.deHidl()) {
+ setScheduler(getBiometricSchedulerForInit(gestureAvailabilityDispatcher,
+ lockoutResetDispatcher));
+ } else {
+ setScheduler(getUserAwareBiometricSchedulerForInit(gestureAvailabilityDispatcher,
+ lockoutResetDispatcher));
+ }
+ mLockoutTracker = new LockoutCache();
+ mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ }
+
+ private BiometricScheduler<IFingerprint, ISession> getBiometricSchedulerForInit(
+ @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ return new BiometricScheduler<>(mHandler,
BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties),
gestureAvailabilityDispatcher,
() -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
- new UserAwareBiometricScheduler.UserSwitchCallback() {
+ new UserSwitchProvider<IFingerprint, ISession>() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new FingerprintStopUserClient(mContext, mLazySession, mToken,
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FingerprintStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken,
userId, mSensorProperties.sensorId,
BiometricLogger.ofUnknown(mContext), mBiometricContext,
() -> mCurrentSession = null);
@@ -152,69 +162,100 @@
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
final int sensorId = mSensorProperties.sensorId;
-
- final AidlResponseHandler resultController;
-
- if (Flags.deHidl()) {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {},
- new AidlResponseHandler.AidlResponseHandlerCallback() {
- @Override
- public void onEnrollSuccess() {
- mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
- newUserId);
- mProvider.scheduleInvalidationRequest(sensorId,
- newUserId);
- }
-
- @Override
- public void onHardwareUnavailable() {
- Slog.e(mTag,
- "Fingerprint sensor hardware unavailable.");
- mCurrentSession = null;
- }
- });
- } else {
- resultController = new AidlResponseHandler(
- mContext, mScheduler, sensorId, newUserId,
- mLockoutTracker, lockoutResetDispatcher,
- mBiometricContext.getAuthSessionCoordinator(), () -> {
- Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE");
- mCurrentSession = null;
- });
- }
-
- final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
- (userIdStarted, newSession, halInterfaceVersion) -> {
- Slog.d(mTag, "New session created for user: "
- + userIdStarted + " with hal version: "
- + halInterfaceVersion);
- mCurrentSession = new AidlSession(halInterfaceVersion,
- newSession, userIdStarted, resultController);
- if (FingerprintUtils.getInstance(sensorId)
- .isInvalidationInProgress(mContext, userIdStarted)) {
- Slog.w(mTag,
- "Scheduling unfinished invalidation request for "
- + "sensor: "
- + sensorId
- + ", user: " + userIdStarted);
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {},
+ new AidlResponseHandler.AidlResponseHandlerCallback() {
+ @Override
+ public void onEnrollSuccess() {
+ mProvider.scheduleLoadAuthenticatorIdsForUser(sensorId,
+ newUserId);
mProvider.scheduleInvalidationRequest(sensorId,
- userIdStarted);
+ newUserId);
}
- };
- return new FingerprintStartUserClient(mContext, mProvider::getHalInstance,
- mToken, newUserId, mSensorProperties.sensorId,
- BiometricLogger.ofUnknown(mContext), mBiometricContext,
- resultController, userStartedCallback);
+ @Override
+ public void onHardwareUnavailable() {
+ Slog.e(TAG,
+ "Fingerprint sensor hardware unavailable.");
+ mCurrentSession = null;
+ }
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId);
}
});
- mLockoutTracker = new LockoutCache();
- mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ }
+
+ private UserAwareBiometricScheduler<ISession, AidlSession>
+ getUserAwareBiometricSchedulerForInit(
+ GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ LockoutResetDispatcher lockoutResetDispatcher) {
+ return new UserAwareBiometricScheduler<>(TAG,
+ BiometricScheduler.sensorTypeFromFingerprintProperties(mSensorProperties),
+ gestureAvailabilityDispatcher,
+ () -> mCurrentSession != null ? mCurrentSession.getUserId() : UserHandle.USER_NULL,
+ new UserAwareBiometricScheduler.UserSwitchCallback() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new FingerprintStopUserClient(mContext,
+ () -> mLazySession.get().getSession(), mToken,
+ userId, mSensorProperties.sensorId,
+ BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ () -> mCurrentSession = null);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
+ final int sensorId = mSensorProperties.sensorId;
+
+ final AidlResponseHandler resultController = new AidlResponseHandler(
+ mContext, mScheduler, sensorId, newUserId,
+ mLockoutTracker, lockoutResetDispatcher,
+ mBiometricContext.getAuthSessionCoordinator(), () -> {
+ Slog.e(TAG, "Fingerprint hardware unavailable.");
+ mCurrentSession = null;
+ });
+
+ return Sensor.this.getStartUserClient(resultController, sensorId,
+ newUserId);
+ }
+ });
+ }
+
+ private FingerprintStartUserClient getStartUserClient(AidlResponseHandler resultController,
+ int sensorId, int newUserId) {
+ final StartUserClient.UserStartedCallback<ISession> userStartedCallback =
+ (userIdStarted, newSession, halInterfaceVersion) -> {
+ Slog.d(TAG, "New fingerprint session created for user: "
+ + userIdStarted + " with hal version: "
+ + halInterfaceVersion);
+ mCurrentSession = new AidlSession(halInterfaceVersion,
+ newSession, userIdStarted, resultController);
+ if (FingerprintUtils.getInstance(sensorId)
+ .isInvalidationInProgress(mContext, userIdStarted)) {
+ Slog.w(TAG,
+ "Scheduling unfinished invalidation request for "
+ + "fingerprint sensor: "
+ + sensorId
+ + ", user: " + userIdStarted);
+ mProvider.scheduleInvalidationRequest(sensorId,
+ userIdStarted);
+ }
+ };
+
+ return new FingerprintStartUserClient(mContext, mProvider::getHalInstance,
+ mToken, newUserId, mSensorProperties.sensorId,
+ BiometricLogger.ofUnknown(mContext), mBiometricContext,
+ resultController, userStartedCallback);
}
protected static FingerprintSensorPropertiesInternal getFingerprintSensorPropertiesInternal(
@@ -267,7 +308,7 @@
biometricStateCallback, mProvider, this);
}
- @NonNull public BiometricScheduler getScheduler() {
+ @NonNull public BiometricScheduler<IFingerprint, ISession> getScheduler() {
return mScheduler;
}
@@ -283,17 +324,17 @@
}
void setTestHalEnabled(boolean enabled) {
- Slog.w(mTag, "setTestHalEnabled: " + enabled);
+ Slog.w(TAG, "Fingerprint setTestHalEnabled: " + enabled);
if (enabled != mTestHalEnabled) {
// The framework should retrieve a new session from the HAL.
try {
if (mCurrentSession != null) {
// TODO(181984005): This should be scheduled instead of directly invoked
- Slog.d(mTag, "Closing old session");
+ Slog.d(TAG, "Closing old fingerprint session");
mCurrentSession.getSession().close();
}
} catch (RemoteException e) {
- Slog.e(mTag, "RemoteException", e);
+ Slog.e(TAG, "RemoteException", e);
}
mCurrentSession = null;
}
@@ -335,7 +376,7 @@
public void onBinderDied() {
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (client instanceof ErrorConsumer) {
- Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ Slog.e(TAG, "Sending fingerprint hardware unavailable error for client: " + client);
final ErrorConsumer errorConsumer = (ErrorConsumer) client;
errorConsumer.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index d3cecd0..4accf8f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -119,7 +119,7 @@
@NonNull private final AuthenticationStateListeners mAuthenticationStateListeners;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
- private final BiometricScheduler mScheduler;
+ private final BiometricScheduler<IBiometricsFingerprint, AidlSession> mScheduler;
private final Handler mHandler;
private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockoutFrameworkImpl mLockoutTracker;
@@ -198,11 +198,11 @@
private final int mSensorId;
@NonNull private final Context mContext;
@NonNull final Handler mHandler;
- @NonNull final BiometricScheduler mScheduler;
+ @NonNull final BiometricScheduler<IBiometricsFingerprint, AidlSession> mScheduler;
@Nullable private Callback mCallback;
HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler,
- @NonNull BiometricScheduler scheduler) {
+ @NonNull BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler) {
mSensorId = sensorId;
mContext = context;
mHandler = handler;
@@ -336,7 +336,7 @@
@NonNull BiometricStateCallback biometricStateCallback,
@NonNull AuthenticationStateListeners authenticationStateListeners,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
- @NonNull BiometricScheduler scheduler,
+ @NonNull BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller,
@@ -389,8 +389,8 @@
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- final BiometricScheduler scheduler =
- new BiometricScheduler(TAG,
+ final BiometricScheduler<IBiometricsFingerprint, AidlSession> scheduler =
+ new BiometricScheduler<>(
BiometricScheduler.sensorTypeFromFingerprintProperties(sensorProps),
gestureAvailabilityDispatcher);
final HalResultController controller = new HalResultController(sensorProps.sensorId,
@@ -533,8 +533,8 @@
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId, boolean force) {
final boolean hasEnrolled =
!getEnrolledFingerprints(mSensorProperties.sensorId, targetUserId).isEmpty();
- final FingerprintUpdateActiveUserClient client =
- new FingerprintUpdateActiveUserClient(mContext, mLazyDaemon, targetUserId,
+ final FingerprintUpdateActiveUserClientLegacy client =
+ new FingerprintUpdateActiveUserClientLegacy(mContext, mLazyDaemon, targetUserId,
mContext.getOpPackageName(), mSensorProperties.sensorId,
createLogger(BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 88dae6f..9232e11 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -140,9 +140,9 @@
private static class TestableBiometricScheduler extends BiometricScheduler {
@NonNull private Fingerprint21UdfpsMock mFingerprint21;
- TestableBiometricScheduler(@NonNull String tag, @NonNull Handler handler,
+ TestableBiometricScheduler(
@Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
+ super(BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher);
}
void init(@NonNull Fingerprint21UdfpsMock fingerprint21) {
@@ -258,7 +258,7 @@
final Handler handler = new Handler(Looper.getMainLooper());
final TestableBiometricScheduler scheduler =
- new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher);
+ new TestableBiometricScheduler(gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
return new Fingerprint21UdfpsMock(context, biometricStateCallback,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index 5c5b992..59e64cd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
import android.os.Build;
import android.os.Environment;
import android.os.RemoteException;
@@ -39,8 +39,8 @@
/**
* Sets the HAL's current active user, and updates the framework's authenticatorId cache.
*/
-public class FingerprintUpdateActiveUserClient extends
- StartUserClient<IBiometricsFingerprint, AidlSession> {
+public class FingerprintUpdateActiveUserClient extends StartUserClient<ISession,
+ AidlSession> {
private static final String TAG = "FingerprintUpdateActiveUserClient";
private static final String FP_DATA_DIR = "fpdata";
@@ -52,19 +52,7 @@
private File mDirectory;
FingerprintUpdateActiveUserClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
- @NonNull String owner, int sensorId,
- @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
- @NonNull Supplier<Integer> currentUserId,
- boolean hasEnrolledBiometrics, @NonNull Map<Integer, Long> authenticatorIds,
- boolean forceUpdateAuthenticatorId) {
- this(context, lazyDaemon, userId, owner, sensorId, logger, biometricContext, currentUserId,
- hasEnrolledBiometrics, authenticatorIds, forceUpdateAuthenticatorId,
- (newUserId, newUser, halInterfaceVersion) -> {});
- }
-
- FingerprintUpdateActiveUserClient(@NonNull Context context,
- @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
+ @NonNull Supplier<ISession> lazyDaemon, int userId,
@NonNull String owner, int sensorId,
@NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
@NonNull Supplier<Integer> currentUserId,
@@ -132,9 +120,10 @@
try {
final int targetId = getTargetUserId();
Slog.d(TAG, "Setting active user: " + targetId);
- getFreshDaemon().setActiveGroup(targetId, mDirectory.getAbsolutePath());
+ HidlToAidlSessionAdapter sessionAdapter = (HidlToAidlSessionAdapter) getFreshDaemon();
+ sessionAdapter.setActiveGroup(targetId, mDirectory.getAbsolutePath());
mAuthenticatorIds.put(targetId, mHasEnrolledBiometrics
- ? getFreshDaemon().getAuthenticatorId() : 0L);
+ ? sessionAdapter.getAuthenticatorIdForUpdateClient() : 0L);
mUserStartedCallback.onUserStarted(targetId, null, 0);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java
new file mode 100644
index 0000000..fc85402
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClientLegacy.java
@@ -0,0 +1,133 @@
+/*
+ * 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.server.biometrics.sensors.fingerprint.hidl;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.os.Build;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.os.SELinux;
+import android.util.Slog;
+
+import com.android.server.biometrics.BiometricsProto;
+import com.android.server.biometrics.log.BiometricContext;
+import com.android.server.biometrics.log.BiometricLogger;
+import com.android.server.biometrics.sensors.ClientMonitorCallback;
+import com.android.server.biometrics.sensors.HalClientMonitor;
+
+import java.io.File;
+import java.util.Map;
+import java.util.function.Supplier;
+
+/**
+ * TODO(b/304604965): Delete this class once Flags.DE_HIDL is ready for release.
+ */
+public class FingerprintUpdateActiveUserClientLegacy extends
+ HalClientMonitor<IBiometricsFingerprint> {
+ private static final String TAG = "FingerprintUpdateActiveUserClient";
+ private static final String FP_DATA_DIR = "fpdata";
+
+ private final Supplier<Integer> mCurrentUserId;
+ private final boolean mForceUpdateAuthenticatorId;
+ private final boolean mHasEnrolledBiometrics;
+ private final Map<Integer, Long> mAuthenticatorIds;
+ private File mDirectory;
+
+ FingerprintUpdateActiveUserClientLegacy(@NonNull Context context,
+ @NonNull Supplier<IBiometricsFingerprint> lazyDaemon, int userId,
+ @NonNull String owner, int sensorId,
+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext,
+ @NonNull Supplier<Integer> currentUserId,
+ boolean hasEnrolledBiometrics, @NonNull Map<Integer, Long> authenticatorIds,
+ boolean forceUpdateAuthenticatorId) {
+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
+ 0 /* cookie */, sensorId, logger, biometricContext);
+ mCurrentUserId = currentUserId;
+ mForceUpdateAuthenticatorId = forceUpdateAuthenticatorId;
+ mHasEnrolledBiometrics = hasEnrolledBiometrics;
+ mAuthenticatorIds = authenticatorIds;
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ if (mCurrentUserId.get() == getTargetUserId() && !mForceUpdateAuthenticatorId) {
+ Slog.d(TAG, "Already user: " + mCurrentUserId + ", returning");
+ callback.onClientFinished(this, true /* success */);
+ return;
+ }
+
+ int firstSdkInt = Build.VERSION.DEVICE_INITIAL_SDK_INT;
+ if (firstSdkInt < Build.VERSION_CODES.BASE) {
+ Slog.e(TAG, "First SDK version " + firstSdkInt + " is invalid; must be "
+ + "at least VERSION_CODES.BASE");
+ }
+ File baseDir;
+ if (firstSdkInt <= Build.VERSION_CODES.O_MR1) {
+ baseDir = Environment.getUserSystemDirectory(getTargetUserId());
+ } else {
+ baseDir = Environment.getDataVendorDeDirectory(getTargetUserId());
+ }
+
+ mDirectory = new File(baseDir, FP_DATA_DIR);
+ if (!mDirectory.exists()) {
+ if (!mDirectory.mkdir()) {
+ Slog.e(TAG, "Cannot make directory: " + mDirectory.getAbsolutePath());
+ callback.onClientFinished(this, false /* success */);
+ return;
+ }
+ // Calling mkdir() from this process will create a directory with our
+ // permissions (inherited from the containing dir). This command fixes
+ // the label.
+ if (!SELinux.restorecon(mDirectory)) {
+ Slog.e(TAG, "Restorecons failed. Directory will have wrong label.");
+ callback.onClientFinished(this, false /* success */);
+ return;
+ }
+ }
+
+ startHalOperation();
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ try {
+ final int targetId = getTargetUserId();
+ Slog.d(TAG, "Setting active user: " + targetId);
+ getFreshDaemon().setActiveGroup(targetId, mDirectory.getAbsolutePath());
+ mAuthenticatorIds.put(targetId, mHasEnrolledBiometrics
+ ? getFreshDaemon().getAuthenticatorId() : 0L);
+ mCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to setActiveGroup: " + e);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public int getProtoEnum() {
+ return BiometricsProto.CM_UPDATE_ACTIVE_USER;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
index 90da74c..47fdcdb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapter.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.os.Handler;
@@ -39,7 +40,7 @@
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.StartUserClient;
import com.android.server.biometrics.sensors.StopUserClient;
-import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.aidl.AidlResponseHandler;
@@ -71,37 +72,33 @@
}
};
- public HidlToAidlSensorAdapter(@NonNull String tag, @NonNull FingerprintProvider provider,
- @NonNull Context context, @NonNull Handler handler,
+ public HidlToAidlSensorAdapter(@NonNull FingerprintProvider provider,
+ @NonNull Context context,
+ @NonNull Handler handler,
@NonNull SensorProps prop,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresHardwareAuthToken,
@NonNull Runnable internalCleanupRunnable) {
- this(tag, provider, context, handler, prop, lockoutResetDispatcher,
- gestureAvailabilityDispatcher, biometricContext,
+ this(provider, context, handler, prop, lockoutResetDispatcher, biometricContext,
resetLockoutRequiresHardwareAuthToken, internalCleanupRunnable,
new AuthSessionCoordinator(), null /* daemon */,
null /* onEnrollSuccessCallback */);
}
@VisibleForTesting
- HidlToAidlSensorAdapter(@NonNull String tag, @NonNull FingerprintProvider provider,
+ HidlToAidlSensorAdapter(@NonNull FingerprintProvider provider,
@NonNull Context context, @NonNull Handler handler,
@NonNull SensorProps prop,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
@NonNull BiometricContext biometricContext,
boolean resetLockoutRequiresHardwareAuthToken,
@NonNull Runnable internalCleanupRunnable,
@NonNull AuthSessionCoordinator authSessionCoordinator,
@Nullable IBiometricsFingerprint daemon,
@Nullable AidlResponseHandler.AidlResponseHandlerCallback aidlResponseHandlerCallback) {
- super(tag, provider, context, handler, getFingerprintSensorPropertiesInternal(prop,
+ super(provider, context, handler, getFingerprintSensorPropertiesInternal(prop,
new ArrayList<>(), resetLockoutRequiresHardwareAuthToken),
- lockoutResetDispatcher,
- gestureAvailabilityDispatcher,
biometricContext, null /* session */);
mLockoutResetDispatcher = lockoutResetDispatcher;
mInternalCleanupRunnable = internalCleanupRunnable;
@@ -127,7 +124,7 @@
@Override
public void serviceDied(long cookie) {
- Slog.d(TAG, "HAL died.");
+ Slog.d(TAG, "Fingerprint HAL died.");
mSession = null;
mDaemon = null;
}
@@ -139,12 +136,12 @@
}
@Override
- public void init(GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- LockoutResetDispatcher lockoutResetDispatcher) {
+ public void init(@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
setLazySession(this::getSession);
- setScheduler(new UserAwareBiometricScheduler(TAG,
+ setScheduler(new BiometricScheduler<ISession, AidlSession>(getHandler(),
BiometricScheduler.sensorTypeFromFingerprintProperties(getSensorProperties()),
- gestureAvailabilityDispatcher, () -> mCurrentUserId, getUserSwitchCallback()));
+ gestureAvailabilityDispatcher, () -> mCurrentUserId, getUserSwitchProvider()));
mLockoutTracker = new LockoutFrameworkImpl(getContext(),
userId -> mLockoutResetDispatcher.notifyLockoutResetCallbacks(
getSensorProperties().sensorId), getHandler());
@@ -152,6 +149,7 @@
@Override
@Nullable
+ @VisibleForTesting
protected AidlSession getSessionForUser(int userId) {
if (mSession != null && mSession.getUserId() == userId) {
return mSession;
@@ -217,21 +215,18 @@
}
mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
-
- Slog.d(TAG, "Fingerprint HAL ready");
-
scheduleLoadAuthenticatorIds();
mInternalCleanupRunnable.run();
return mDaemon;
}
- private UserAwareBiometricScheduler.UserSwitchCallback getUserSwitchCallback() {
- return new UserAwareBiometricScheduler.UserSwitchCallback() {
+ private UserSwitchProvider<ISession, AidlSession> getUserSwitchProvider() {
+ return new UserSwitchProvider<>() {
@NonNull
@Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new StopUserClient<IBiometricsFingerprint>(getContext(),
- HidlToAidlSensorAdapter.this::getIBiometricsFingerprint,
+ public StopUserClient<AidlSession> getStopUserClient(int userId) {
+ return new StopUserClient<>(getContext(),
+ HidlToAidlSensorAdapter.this::getSession,
null /* token */, userId, getSensorProperties().sensorId,
BiometricLogger.ofUnknown(getContext()), getBiometricContext(),
() -> {
@@ -258,7 +253,7 @@
@NonNull
@Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
+ public StartUserClient<ISession, AidlSession> getStartUserClient(int newUserId) {
return getFingerprintUpdateActiveUserClient(newUserId,
false /* forceUpdateAuthenticatorId */);
}
@@ -268,7 +263,7 @@
private FingerprintUpdateActiveUserClient getFingerprintUpdateActiveUserClient(int newUserId,
boolean forceUpdateAuthenticatorIds) {
return new FingerprintUpdateActiveUserClient(getContext(),
- this::getIBiometricsFingerprint, newUserId, TAG,
+ () -> getSession().getSession(), newUserId, TAG,
getSensorProperties().sensorId, BiometricLogger.ofUnknown(getContext()),
getBiometricContext(), () -> mCurrentUserId,
!FingerprintUtils.getInstance(getSensorProperties().sensorId)
@@ -290,7 +285,7 @@
}
@VisibleForTesting void handleUserChanged(int newUserId) {
- Slog.d(TAG, "User changed. Current user is " + newUserId);
+ Slog.d(TAG, "User changed. Current user for fingerprint sensor is " + newUserId);
mSession = null;
mCurrentUserId = newUserId;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
index 2fc00e1..b469752 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSessionAdapter.java
@@ -209,6 +209,14 @@
return null;
}
+ public long getAuthenticatorIdForUpdateClient() throws RemoteException {
+ return mSession.get().getAuthenticatorId();
+ }
+
+ public void setActiveGroup(int userId, String absolutePath) throws RemoteException {
+ mSession.get().setActiveGroup(userId, absolutePath);
+ }
+
private void setCallback(AidlResponseHandler aidlResponseHandler) {
mHidlToAidlCallbackConverter = new HidlToAidlCallbackConverter(aidlResponseHandler);
try {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index fbac924..9cf9119 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 @@
// 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 734381b..087cacf 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.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.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.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.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 @@
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 @@
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 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 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 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
@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 @@
// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
}
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 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 @@
}
};
- 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 @@
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();
+ if (mCdsi != null) {
+ boolean active = mCdsi.setReduceBrightColorsListener(
+ new ReduceBrightColorsListener() {
+ @Override
+ public void onReduceBrightColorsActivationChanged(boolean activated,
+ boolean userInitiated) {
+ applyReduceBrightColorsSplineAdjustment();
- }
+ }
- @Override
- public void onReduceBrightColorsStrengthChanged(int strength) {
+ @Override
+ public void onReduceBrightColorsStrengthChanged(int strength) {
+ applyReduceBrightColorsSplineAdjustment();
+ }
+ });
+ if (active) {
applyReduceBrightColorsSplineAdjustment();
}
- });
- if (active) {
- applyReduceBrightColorsSplineAdjustment();
}
} else {
mCdsi = null;
@@ -737,27 +627,17 @@
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 @@
*/
@Override
public boolean isProximitySensorAvailable() {
- return mProximitySensor != null;
+ return mDisplayPowerProximityStateController.isProximitySensorAvailable();
}
/**
@@ -818,64 +698,6 @@
}
}
- @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 @@
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 @@
@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 @@
* 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 @@
.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 @@
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 @@
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 @@
/**
* 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 @@
mAutomaticBrightnessController.stop();
}
- if (mBrightnessSetting != null) {
- mBrightnessSetting.unregisterListener(mBrightnessSettingListener);
- }
+ mDisplayBrightnessController.stop();
mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
}
@@ -1073,11 +905,11 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
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 @@
/** 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 @@
if (mScreenOffBrightnessSensorController != null) {
mScreenOffBrightnessSensorController.stop();
}
+
if (mDisplayWhiteBalanceController != null) {
mDisplayWhiteBalanceController.setEnabled(false);
}
-
}
// Call from handler thread
@@ -1476,7 +1314,6 @@
final boolean mustNotify;
final int previousPolicy;
boolean mustInitialize = false;
- int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
mTempBrightnessEvent.reset();
SparseArray<DisplayPowerControllerInterface> displayBrightnessFollowers;
@@ -1491,7 +1328,7 @@
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 @@
} else if (mPendingRequestChangedLocked) {
previousPolicy = mPowerRequest.policy;
mPowerRequest.copyFrom(mPendingRequestLocked);
- updatePendingProximityRequestsLocked();
+ mDisplayPowerProximityStateController.updatePendingProximityRequestsLocked();
mPendingRequestChangedLocked = false;
mDisplayReadyLocked = false;
} else {
@@ -1512,105 +1349,8 @@
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 @@
// 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();
+
+ 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);
}
- 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();
-
- // 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;
- }
-
- 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
+ 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);
}
- updateScreenBrightnessSetting = mCurrentScreenBrightnessSetting != brightnessState;
- mAppliedAutoBrightness = true;
- mBrightnessReasonTemp.setReason(BrightnessReason.REASON_AUTOMATIC);
- if (mScreenOffBrightnessSensorController != null) {
- mScreenOffBrightnessSensorController.setLightSensorEnabled(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 @@
// 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 @@
// 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 @@
: 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 @@
// 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 @@
// 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 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 @@
// 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 @@
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 @@
}
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 @@
? 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 @@
if (mBrightnessEventRingBuffer != null) {
mBrightnessEventRingBuffer.append(newEvent);
}
+ if (isRbcEvent) {
+ mRbcEventRingBuffer.append(newEvent);
+ }
+
}
// Update display white-balance.
@@ -2092,6 +1769,7 @@
// 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 @@
}
// 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 @@
}
// 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 @@
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 @@
*/
@Override
public void ignoreProximitySensorUntilChanged() {
- mHandler.sendEmptyMessage(MSG_IGNORE_PROXIMITY);
+ mDisplayPowerProximityStateController.ignoreProximitySensorUntilChanged();
}
@Override
@@ -2210,21 +1880,27 @@
@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 @@
}
}
- private boolean saveBrightnessInfo(float brightness) {
- return saveBrightnessInfo(brightness, brightness);
+ @Override
+ public void onBootCompleted() {
+ Message msg = mHandler.obtainMessage(MSG_BOOT_COMPLETED);
+ mHandler.sendMessageAtTime(msg, mClock.uptimeMillis());
}
- private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
+ 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) {
- 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 @@
mBrightnessRangeController.getTransitionPoint());
changed |=
mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.brightnessMaxReason,
- mBrightnessThrottler.getBrightnessMaxReason());
-
+ mBrightnessClamperController.getBrightnessMaxReason());
return changed;
}
}
@@ -2288,27 +1974,18 @@
}
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 @@
}
}
+ 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 (mPowerState.getScreenState() != state
- || mReportedScreenStateToPolicy == REPORTED_TO_POLICY_UNREPORTED) {
+ // 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 && !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 @@
}
}
- 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 @@
// 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 @@
}
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
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());
+ public int getDisplayId() {
+ return mDisplayId;
}
- private void updateScreenBrightnessSetting(float brightnessValue) {
- if (!isValidBrightnessValue(brightnessValue)
- || brightnessValue == mCurrentScreenBrightnessSetting) {
- return;
- }
- setCurrentScreenBrightness(brightnessValue);
- setBrightness(brightnessValue);
+ @Override
+ public int getLeadDisplayId() {
+ return mLeadDisplayId;
}
- private void setCurrentScreenBrightness(float brightnessValue) {
- if (brightnessValue != mCurrentScreenBrightnessSetting) {
- mCurrentScreenBrightnessSetting = brightnessValue;
- postBrightnessChangeRunnable();
+ @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);
+ }
}
- }
-
- 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);
- }
- }
-
- 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;
- }
-
- // 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;
- }
- 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 @@
|| 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 @@
mAutomaticBrightnessController.getLastSensorTimestamps());
}
- private float convertToNits(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.convertToNits(brightness);
}
- private float convertToAdjustedNits(float brightness) {
- if (mAutomaticBrightnessController == null) {
- return BrightnessMappingStrategy.INVALID_NITS;
+ @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.convertToAdjustedNits(brightness);
- }
-
- private float getBrightnessFromNits(float nits) {
- if (mAutomaticBrightnessController == null) {
- return PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
- 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 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());
}
- }
-
- 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);
- }
- };
-
- /**
- * 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 @@
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 @@
}
pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
-
mHandler.runWithScissors(() -> dumpLocal(pw), 1000);
}
@@ -3090,35 +2585,9 @@
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 @@
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 @@
dumpBrightnessEvents(pw);
}
+ dumpRbcEvents(pw);
+
if (mScreenOffBrightnessSensorController != null) {
mScreenOffBrightnessSensorController.dump(pw);
}
@@ -3173,21 +2643,30 @@
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,14 +2707,20 @@
}
}
- 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;
+ }
+
+ 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 static float clampAutoBrightnessAdjustment(float value) {
- return MathUtils.constrain(value, -1.0f, 1.0f);
- }
private void noteScreenState(int screenState) {
// Log screen state change with display id
@@ -3363,20 +2848,21 @@
// 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 @@
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 @@
}
}
+ /**
+ * 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 @@
updatePowerState();
break;
- case MSG_PROXIMITY_SENSOR_DEBOUNCED:
- debounceProximitySensor();
- break;
-
case MSG_SCREEN_ON_UNBLOCKED:
if (mPendingScreenOnUnblocker == msg.obj) {
unblockScreenOn();
@@ -3432,27 +2926,38 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 2d860c0..0000000
--- 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 465584c..403dfbe 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 @@
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 c9569cb..a2319a8 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 @@
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 @@
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 50e9533..ad3deff 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.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 @@
* 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 @@
}
@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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
// 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 @@
synchronized (mLock) {
mSupportedModesByDisplay.remove(displayId);
mDefaultModeByDisplay.remove(displayId);
+ mSettingsObserver.removeRefreshRateSetting(displayId);
}
updateLayoutLimitedFrameRate(displayId, null);
removeUserSettingDisplayPreferredSize(displayId);
@@ -1409,6 +1445,7 @@
}
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 7e990c6..380106b 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 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 36dac83..bc7205a 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.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 @@
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 @@
+ 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 @@
}
@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 @@
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 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 @@
}
}
- 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 829b660..dd9204c 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 @@
void setPointerSpeed(int speed);
- void setPointerAcceleration(float acceleration);
+ void setMousePointerAccelerationEnabled(boolean enabled);
void setTouchpadPointerSpeed(int speed);
@@ -351,7 +351,7 @@
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 25ec683..4db9ead 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 @@
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 fb57c09..58a68f2a 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 @@
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 aa638aa..e507c6b 100644
--- a/services/core/java/com/android/server/inputmethod/OWNERS
+++ b/services/core/java/com/android/server/inputmethod/OWNERS
@@ -6,5 +6,8 @@
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 d02b6f4..171fbb6 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 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.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.LocationUsageLogger;
import com.android.server.location.injector.SettingsHelper;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Collection;
/**
@@ -91,6 +95,9 @@
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 @@
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 c772e08..5df0de8 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.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 @@
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 0c2eee5..542b3b0 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 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.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 @@
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 @@
}
@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);
}
@@ -2118,11 +2140,10 @@
Slogf.d(TAG, "CE storage for user %d is already unlocked", userId);
return;
}
- final UserInfo userInfo = mUserManager.getUserInfo(userId);
final String userType = isUserSecure(userId) ? "secured" : "unsecured";
final byte[] secret = sp.deriveFileBasedEncryptionKey();
try {
- mStorageManager.unlockCeStorage(userId, userInfo.serialNumber, secret);
+ mStorageManager.unlockCeStorage(userId, secret);
Slogf.i(TAG, "Unlocked CE storage for %s user %d", userType, userId);
} catch (RemoteException e) {
Slogf.wtf(TAG, e, "Failed to unlock CE storage for %s user %d", userType, userId);
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 06a8d98..e048522 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 @@
.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 @@
} 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 @@
"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 @@
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 @@
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 6deda46..f6571d9 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 @@
}
@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 @@
}
@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 @@
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 @@
MediaProjection projection;
final long callingToken = Binder.clearCallingIdentity();
try {
- projection = getProjectionInternal(uid, packageName);
+ projection = getProjectionInternal(processUid, packageName);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -869,12 +869,13 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 e3880c3..deb95d8 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 @@
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 @@
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 7aa7b7e..9ddc362 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.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.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 @@
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 db64a75..afbf08d 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 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 @@
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 @@
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 @@
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,7 +461,10 @@
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);
+
if (setConfigLocked(newConfig, origin, reason, rule.component, true, callingUid)) {
return rule.id;
} else {
@@ -461,6 +473,56 @@
}
}
+ 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;
+ }
+ if (addedRule.getType() == AutomaticZenRule.TYPE_BEDTIME) {
+ // Delete a built-in disabled "Sleeping" rule when a BEDTIME rule is added; it may have
+ // smarter triggers and it will prevent confusion about which one to use.
+ // Note: we must not verify canManageAutomaticZenRule here, since most likely they
+ // won't have the same owner (sleeping - system; bedtime - DWB).
+ ZenRule sleepingRule = config.automaticRules.get(
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
+ if (sleepingRule != null
+ && !sleepingRule.enabled
+ && sleepingRule.canBeUpdatedByApp() /* meaning it's not user-customized */) {
+ config.automaticRules.remove(ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
+ }
+ }
+ }
+
public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
@ConfigChangeOrigin int origin, String reason, int callingUid) {
ZenModeConfig newConfig;
@@ -623,7 +685,7 @@
ZenRule rule = new ZenRule();
rule.id = implicitRuleId(pkg);
rule.pkg = pkg;
- rule.creationTime = System.currentTimeMillis();
+ rule.creationTime = mClock.millis();
Binder.withCleanCallingIdentity(() -> {
try {
@@ -643,7 +705,7 @@
rule.condition = null;
rule.conditionId = new Uri.Builder()
.scheme(Condition.SCHEME)
- .authority("android")
+ .authority(PACKAGE_ANDROID)
.appendPath("implicit")
.appendPath(pkg)
.build();
@@ -672,7 +734,9 @@
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())) {
@@ -702,12 +766,44 @@
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;
@@ -898,7 +994,7 @@
// 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;
}
@@ -1358,7 +1454,7 @@
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) {
@@ -1377,6 +1473,10 @@
// reset zen automatic rules to default on restore or upgrade if:
// - doesn't already have default rules and
// - all previous automatic rules were disabled
+ //
+ // Note: we don't need to check to avoid restoring the Sleeping rule if there is a
+ // TYPE_BEDTIME rule because the config is from an old version and thus by
+ // definition cannot have a rule with TYPE_BEDTIME (or any other type).
config.automaticRules = new ArrayMap<>();
for (ZenRule rule : mDefaultConfig.automaticRules.values()) {
config.automaticRules.put(rule.id, rule);
@@ -1394,6 +1494,12 @@
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,
@@ -1411,7 +1517,7 @@
if (forBackup && mConfigs.keyAt(i) != userId) {
continue;
}
- mConfigs.valueAt(i).writeXml(out, version);
+ mConfigs.valueAt(i).writeXml(out, version, forBackup);
}
}
}
@@ -1443,28 +1549,51 @@
}
/**
- * 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);
}
}
}
- setConfigLocked(newConfig, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "cleanUpZenRules",
- Process.SYSTEM_UID);
+
+ 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);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index dd9541e..92be4ee 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 @@
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 @@
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 @@
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 127bf49..9915554 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 @@
"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 a4af5e7..3e5759a 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.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 @@
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 @@
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 @@
// 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 @@
}
@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 @@
}
}
- 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 @@
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 @@
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 a9118d4..fdcd28b 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_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 @@
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 @@
binderUid, unarchiveId));
}
- session.reportUnarchivalStatus(unarchiveId, status, requiredStorageBytes,
+ session.reportUnarchivalStatus(status, unarchiveId, requiredStorageBytes,
userActionIntent);
}
}
@@ -1828,9 +1829,23 @@
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 @@
} else {
mNotification = null;
}
+ mUserId = userId;
+ mPackageArchiver = packageArchiver;
+ mFlags = flags;
}
private String getDeviceOwnerDeletedPackageMsg() {
@@ -1883,6 +1901,11 @@
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 3adeb4b..446c629 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.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.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 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/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index 7d87d1b..cef3244 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -193,7 +193,7 @@
}
try {
- sm.prepareUserStorage(volumeUuid, user.id, user.serialNumber, flags);
+ sm.prepareUserStorage(volumeUuid, user.id, flags);
synchronized (mPm.mInstallLock) {
appDataHelper.reconcileAppsDataLI(volumeUuid, user.id, flags,
true /* migrateAppData */);
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 8adb566..4c42c2d 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -92,7 +92,7 @@
volumeUuid, userId, flags, isNewUser);
try {
// Prepare CE and/or DE storage.
- storage.prepareUserStorage(volumeUuid, userId, userSerial, flags);
+ storage.prepareUserStorage(volumeUuid, userId, flags);
// Ensure that the data directories of a removed user with the same ID are not being
// reused. New users must get fresh data directories, to avoid leaking data.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 75b4531..c1b7489 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 @@
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);
@@ -5136,7 +5146,7 @@
t.traceBegin("createUserStorageKeys");
final StorageManager storage = mContext.getSystemService(StorageManager.class);
- storage.createUserStorageKeys(userId, userInfo.serialNumber, userInfo.isEphemeral());
+ storage.createUserStorageKeys(userId, userInfo.isEphemeral());
t.traceEnd();
// Only prepare DE storage here. CE storage will be prepared later, when the user is
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2128c991..e226953 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.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 @@
// 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 @@
DeviceConfigParameterProvider createDeviceConfigParameterProvider() {
return new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
}
+
+ PowerManagerFlags getFlags() {
+ return new PowerManagerFlags();
+ }
}
/** Interface for checking an app op permission */
@@ -1145,6 +1152,7 @@
mNativeWrapper = injector.createNativeWrapper();
mSystemProperties = injector.createSystemPropertiesWrapper();
mClock = injector.createClock();
+ mFeatureFlags = injector.getFlags();
mInjector = injector;
mHandlerThread = new ServiceThread(TAG,
@@ -4802,6 +4810,7 @@
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 0000000..2295b41
--- /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 0000000..a5a7069
--- /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 0000000..c8c16db
--- /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/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 03f3763..09b19e6 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -190,15 +190,11 @@
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
// in to one common name.
- private static final int MAX_WAKELOCKS_PER_UID;
+ private static final int MAX_WAKELOCKS_PER_UID = isLowRamDevice() ? 40 : 200;
- static {
- if (ActivityManager.isLowRamDeviceStatic()) {
- MAX_WAKELOCKS_PER_UID = 40;
- } else {
- MAX_WAKELOCKS_PER_UID = 200;
- }
- }
+ private static final int CELL_SIGNAL_STRENGTH_LEVEL_COUNT = getCellSignalStrengthLevelCount();
+
+ private static final int MODEM_TX_POWER_LEVEL_COUNT = getModemTxPowerLevelCount();
// Number of transmit power states the Wifi controller can be in.
private static final int NUM_WIFI_TX_LEVELS = 1;
@@ -278,11 +274,9 @@
@VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
@VisibleForTesting
- protected SystemServerCpuThreadReader mSystemServerCpuThreadReader =
- SystemServerCpuThreadReader.create();
+ protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
- private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
- = new KernelMemoryBandwidthStats();
+ private KernelMemoryBandwidthStats mKernelMemoryBandwidthStats;
private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();
private int[] mCpuPowerBracketMap;
private final CpuPowerStatsCollector mCpuPowerStatsCollector;
@@ -323,7 +317,7 @@
private long mLastRpmStatsUpdateTimeMs = -RPM_STATS_UPDATE_FREQ_MS;
/** Container for Rail Energy Data stats. */
- private final RailStats mTmpRailStats = new RailStats();
+ private RailStats mTmpRailStats;
/**
* Estimate UID modem power usage based on their estimated mobile radio active time.
@@ -1031,7 +1025,7 @@
int mPhoneSignalStrengthBin = -1;
int mPhoneSignalStrengthBinRaw = -1;
final StopwatchTimer[] mPhoneSignalStrengthsTimer =
- new StopwatchTimer[CellSignalStrength.getNumSignalStrengthLevels()];
+ new StopwatchTimer[CELL_SIGNAL_STRENGTH_LEVEL_COUNT];
StopwatchTimer mPhoneSignalScanningTimer;
@@ -1723,7 +1717,8 @@
@VisibleForTesting
public BatteryStatsImpl(Clock clock, File historyDirectory, @NonNull Handler handler,
@NonNull PowerStatsUidResolver powerStatsUidResolver) {
- init(clock);
+ mClock = clock;
+ initKernelStatsReaders();
mBatteryStatsConfig = new BatteryStatsConfig.Builder().build();
mHandler = handler;
mPowerStatsUidResolver = powerStatsUidResolver;
@@ -1748,13 +1743,19 @@
mCpuPowerStatsCollector = null;
}
- private void init(Clock clock) {
- mClock = clock;
- mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(true, clock);
- mCpuUidFreqTimeReader = new KernelCpuUidFreqTimeReader(true, clock);
- mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, clock);
- mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, clock);
+ private void initKernelStatsReaders() {
+ if (!isKernelStatsAvailable()) {
+ return;
+ }
+
+ mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(true, mClock);
+ mCpuUidFreqTimeReader = new KernelCpuUidFreqTimeReader(true, mClock);
+ mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, mClock);
+ mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, mClock);
mKernelWakelockReader = new KernelWakelockReader();
+ mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+ mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats();
+ mTmpRailStats = new RailStats();
}
/**
@@ -5878,7 +5879,7 @@
@GuardedBy("this")
void stopAllPhoneSignalStrengthTimersLocked(int except, long elapsedRealtimeMs) {
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
if (i == except) {
continue;
}
@@ -8450,7 +8451,7 @@
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
- mBsi.mOnBatteryTimeBase, ModemActivityInfo.getNumTxPowerLevels());
+ mBsi.mOnBatteryTimeBase, mBsi.MODEM_TX_POWER_LEVEL_COUNT);
}
return mModemControllerActivity;
}
@@ -10896,7 +10897,8 @@
@NonNull UserInfoProvider userInfoProvider, @NonNull PowerProfile powerProfile,
@NonNull CpuScalingPolicies cpuScalingPolicies,
@NonNull PowerStatsUidResolver powerStatsUidResolver) {
- init(clock);
+ mClock = clock;
+ initKernelStatsReaders();
mBatteryStatsConfig = config;
mMonotonicClock = monotonicClock;
@@ -10992,7 +10994,7 @@
mDeviceLightIdlingTimer = new StopwatchTimer(mClock, null, -15, null, mOnBatteryTimeBase);
mDeviceIdlingTimer = new StopwatchTimer(mClock, null, -12, null, mOnBatteryTimeBase);
mPhoneOnTimer = new StopwatchTimer(mClock, null, -3, null, mOnBatteryTimeBase);
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(mClock, null, -200 - i, null,
mOnBatteryTimeBase);
}
@@ -11012,7 +11014,7 @@
mBluetoothActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
mModemActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
- ModemActivityInfo.getNumTxPowerLevels());
+ MODEM_TX_POWER_LEVEL_COUNT);
mMobileRadioActiveTimer = new StopwatchTimer(mClock, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClock, null, -401, null,
mOnBatteryTimeBase);
@@ -11611,7 +11613,7 @@
mFlashlightOnTimer.reset(false, elapsedRealtimeUs);
mCameraOnTimer.reset(false, elapsedRealtimeUs);
mBluetoothScanTimer.reset(false, elapsedRealtimeUs);
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
mPhoneSignalStrengthsTimer[i].reset(false, elapsedRealtimeUs);
}
mPhoneSignalScanningTimer.reset(false, elapsedRealtimeUs);
@@ -11834,7 +11836,7 @@
private String[] mWifiIfaces = EmptyArray.STRING;
@GuardedBy("mWifiNetworkLock")
- private NetworkStats mLastWifiNetworkStats = new NetworkStats(0, -1);
+ private NetworkStats mLastWifiNetworkStats;
private final Object mModemNetworkLock = new Object();
@@ -11842,7 +11844,7 @@
private String[] mModemIfaces = EmptyArray.STRING;
@GuardedBy("mModemNetworkLock")
- private NetworkStats mLastModemNetworkStats = new NetworkStats(0, -1);
+ private NetworkStats mLastModemNetworkStats;
@VisibleForTesting
protected NetworkStats readMobileNetworkStatsLocked(
@@ -11875,7 +11877,9 @@
synchronized (mWifiNetworkLock) {
final NetworkStats latestStats = readWifiNetworkStatsLocked(networkStatsManager);
if (latestStats != null) {
- delta = latestStats.subtract(mLastWifiNetworkStats);
+ delta = mLastWifiNetworkStats != null
+ ? latestStats.subtract(mLastWifiNetworkStats)
+ : latestStats.subtract(new NetworkStats(0, -1));
mLastWifiNetworkStats = latestStats;
}
}
@@ -12248,7 +12252,9 @@
synchronized (mModemNetworkLock) {
final NetworkStats latestStats = readMobileNetworkStatsLocked(networkStatsManager);
if (latestStats != null) {
- delta = latestStats.subtract(mLastModemNetworkStats);
+ delta = latestStats.subtract(mLastModemNetworkStats != null
+ ? mLastModemNetworkStats
+ : new NetworkStats(0, -1));
mLastModemNetworkStats = latestStats;
}
}
@@ -12301,7 +12307,7 @@
deltaInfo.getSleepTimeMillis());
mModemActivity.getOrCreateRxTimeCounter()
.increment(deltaInfo.getReceiveTimeMillis(), elapsedRealtimeMs);
- for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
+ for (int lvl = 0; lvl < MODEM_TX_POWER_LEVEL_COUNT; lvl++) {
mModemActivity.getOrCreateTxTimeCounters()[lvl]
.increment(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl),
elapsedRealtimeMs);
@@ -12318,8 +12324,8 @@
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE)
+ deltaInfo.getReceiveTimeMillis() *
mPowerProfile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
- for (int i = 0; i < Math.min(ModemActivityInfo.getNumTxPowerLevels(),
- CellSignalStrength.getNumSignalStrengthLevels()); i++) {
+ for (int i = 0; i < Math.min(MODEM_TX_POWER_LEVEL_COUNT,
+ CELL_SIGNAL_STRENGTH_LEVEL_COUNT); i++) {
energyUsed += deltaInfo.getTransmitDurationMillisAtPowerLevel(i)
* mPowerProfile.getAveragePower(
PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
@@ -12441,7 +12447,7 @@
}
if (totalTxPackets > 0 && entry.getTxPackets() > 0) {
- for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels();
+ for (int lvl = 0; lvl < MODEM_TX_POWER_LEVEL_COUNT;
lvl++) {
long txMs = entry.getTxPackets()
* deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
@@ -12550,7 +12556,7 @@
&& deltaInfo.getSpecificInfoFrequencyRange(0)
== ServiceState.FREQUENCY_RANGE_UNKNOWN) {
// Specific info data unavailable. Proportionally smear Rx and Tx times across each RAT.
- final int levelCount = CellSignalStrength.getNumSignalStrengthLevels();
+ final int levelCount = CELL_SIGNAL_STRENGTH_LEVEL_COUNT;
long[] perSignalStrengthActiveTimeMs = new long[levelCount];
long totalActiveTimeMs = 0;
@@ -12726,13 +12732,13 @@
return;
}
int levelMaxTimeSpent = 0;
- for (int i = 1; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
+ for (int i = 1; i < MODEM_TX_POWER_LEVEL_COUNT; i++) {
if (activityInfo.getTransmitDurationMillisAtPowerLevel(i)
> activityInfo.getTransmitDurationMillisAtPowerLevel(levelMaxTimeSpent)) {
levelMaxTimeSpent = i;
}
}
- if (levelMaxTimeSpent == ModemActivityInfo.getNumTxPowerLevels() - 1) {
+ if (levelMaxTimeSpent == MODEM_TX_POWER_LEVEL_COUNT - 1) {
mHistory.recordState2StartEvent(elapsedRealtimeMs, uptimeMs,
HistoryItem.STATE2_CELLULAR_HIGH_TX_POWER_FLAG);
}
@@ -14821,12 +14827,12 @@
timeInRatMs[i] = getPhoneDataConnectionTime(i, rawRealTimeUs, which) / 1000;
}
long[] timeInRxSignalStrengthLevelMs =
- new long[CellSignalStrength.getNumSignalStrengthLevels()];
+ new long[CELL_SIGNAL_STRENGTH_LEVEL_COUNT];
for (int i = 0; i < timeInRxSignalStrengthLevelMs.length; i++) {
timeInRxSignalStrengthLevelMs[i] =
getPhoneSignalStrengthTime(i, rawRealTimeUs, which) / 1000;
}
- long[] txTimeMs = new long[Math.min(ModemActivityInfo.getNumTxPowerLevels(),
+ long[] txTimeMs = new long[Math.min(MODEM_TX_POWER_LEVEL_COUNT,
counter.getTxTimeCounters().length)];
long totalTxTimeMs = 0;
for (int i = 0; i < txTimeMs.length; i++) {
@@ -15458,7 +15464,7 @@
public Constants(Handler handler) {
super(handler);
- if (ActivityManager.isLowRamDeviceStatic()) {
+ if (isLowRamDevice()) {
MAX_HISTORY_FILES = DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE;
MAX_HISTORY_BUFFER = DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB * 1024;
} else {
@@ -15528,12 +15534,10 @@
KEY_PROC_STATE_CHANGE_COLLECTION_DELAY_MS,
DEFAULT_PROC_STATE_CHANGE_COLLECTION_DELAY_MS);
MAX_HISTORY_FILES = mParser.getInt(KEY_MAX_HISTORY_FILES,
- ActivityManager.isLowRamDeviceStatic() ?
- DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE
- : DEFAULT_MAX_HISTORY_FILES);
+ isLowRamDevice() ? DEFAULT_MAX_HISTORY_FILES_LOW_RAM_DEVICE
+ : DEFAULT_MAX_HISTORY_FILES);
MAX_HISTORY_BUFFER = mParser.getInt(KEY_MAX_HISTORY_BUFFER_KB,
- ActivityManager.isLowRamDeviceStatic() ?
- DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
+ isLowRamDevice() ? DEFAULT_MAX_HISTORY_BUFFER_LOW_RAM_DEVICE_KB
: DEFAULT_MAX_HISTORY_BUFFER_KB)
* 1024;
final String perUidModemModel = mParser.getString(KEY_PER_UID_MODEM_POWER_MODEL,
@@ -16014,7 +16018,7 @@
mDeviceLightIdlingTimer.readSummaryFromParcelLocked(in);
mDeviceIdlingTimer.readSummaryFromParcelLocked(in);
mPhoneOnTimer.readSummaryFromParcelLocked(in);
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
mPhoneSignalScanningTimer.readSummaryFromParcelLocked(in);
@@ -16520,7 +16524,7 @@
mDeviceLightIdlingTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mDeviceIdlingTimer.writeSummaryFromParcelLocked(out, nowRealtime);
mPhoneOnTimer.writeSummaryFromParcelLocked(out, nowRealtime);
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, nowRealtime);
}
mPhoneSignalScanningTimer.writeSummaryFromParcelLocked(out, nowRealtime);
@@ -17015,7 +17019,7 @@
mDeviceIdlingTimer.logState(pr, " ");
pr.println("*** Phone timer:");
mPhoneOnTimer.logState(pr, " ");
- for (int i = 0; i < CellSignalStrength.getNumSignalStrengthLevels(); i++) {
+ for (int i = 0; i < CELL_SIGNAL_STRENGTH_LEVEL_COUNT; i++) {
pr.println("*** Phone signal strength #" + i + ":");
mPhoneSignalStrengthsTimer[i].logState(pr, " ");
}
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 32656b1..c3221e4 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 @@
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 @@
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);
}
- powerCalculator.calculate(batteryUsageStatsBuilder, stats, realtimeUs, uptimeUs, query);
+
+ if ((query.getFlags()
+ & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY) != 0) {
+ batteryUsageStatsBuilder.setBatteryHistory(stats.copyHistory());
+ }
}
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 8d93408..13f1141 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 @@
ipw.println();
}
- PackageWatchdog.getInstance(mContext).dump(ipw);
});
+ PackageWatchdog.getInstance(mContext).dump(ipw);
}
@AnyThread
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 5d716fc..e3eb5b5 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1891,7 +1891,8 @@
};
}
- private final PackageMonitor mPackageMonitor = new PackageMonitor() {
+ @VisibleForTesting
+ final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
public void onSomePackagesChanged() {
refreshAgentList(UserHandle.USER_ALL);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 58acbe0..b384725 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.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 @@
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 @@
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 @@
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 @@
}
}
+ @GuardedBy("mLock")
private void buildHardwareListLocked() {
mHardwareList.clear();
for (int i = 0; i < mConnections.size(); ++i) {
@@ -301,6 +315,7 @@
}
}
+ @GuardedBy("mLock")
private boolean checkUidChangedLocked(
Connection connection, int callingUid, int resolvedUserId) {
Integer connectionCallingUid = connection.getCallingUidLocked();
@@ -496,6 +511,7 @@
}
}
+ @GuardedBy("mLock")
private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) {
for (TvInputHardwareInfo hardwareInfo : mHardwareList) {
if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI
@@ -506,6 +522,7 @@
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 @@
return false;
}
+ @GuardedBy("mLock")
private void processPendingHdmiDeviceEventsLocked() {
for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) {
Message msg = it.next();
@@ -611,6 +629,7 @@
}
+ @GuardedBy("mLock")
private void processPendingTvInputInfoEventsLocked() {
for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) {
Message msg = it.next();
@@ -748,6 +767,7 @@
// *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 @@
}
}
+ @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 @@
+ " }";
}
+ @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 @@
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 @@
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 @@
}
}
};
+ @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 @@
/**
* 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 @@
}
}
+ @GuardedBy("mImplLock")
private boolean updateAudioSourceLocked() {
if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
return false;
@@ -1214,6 +1266,7 @@
: !mAudioSource.equals(previousSource);
}
+ @GuardedBy("mImplLock")
private boolean updateAudioSinkLocked() {
if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
return false;
@@ -1339,16 +1392,22 @@
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 9213d96..ed04e5f 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 @@
@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 @@
// Auto-generated class
mFeatureFlags = new FeatureFlagsImpl();
+ mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl();
}
@NonNull
@@ -69,11 +71,23 @@
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 54c97dd..3094b18 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 @@
// 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 @@
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 @@
// 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 0000000..5f4852f
--- /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 0000000..a79f188
--- /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 7f129ea..d32e5cc 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 java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
/** @hide */
@@ -86,7 +85,6 @@
* <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 @@
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 @@
networkRecord,
subscriptionGroup,
snapshot,
- currentlySelected,
+ isSelected,
carrierConfig)) {
return priorityIndex;
}
@@ -140,12 +138,9 @@
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 @@
if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps()
|| (caps.getLinkUpstreamBandwidthKbps()
< networkPriority.getMinEntryUpstreamBandwidthKbps()
- && !isSelectedUnderlyingNetwork)) {
+ && !isSelected)) {
return false;
}
@@ -167,7 +162,7 @@
< networkPriority.getMinExitDownstreamBandwidthKbps()
|| (caps.getLinkDownstreamBandwidthKbps()
< networkPriority.getMinEntryDownstreamBandwidthKbps()
- && !isSelectedUnderlyingNetwork)) {
+ && !isSelected)) {
return false;
}
@@ -191,7 +186,7 @@
return checkMatchesWifiPriorityRule(
(VcnWifiUnderlyingNetworkTemplate) networkPriority,
networkRecord,
- currentlySelected,
+ isSelected,
carrierConfig);
}
@@ -214,7 +209,7 @@
public static boolean checkMatchesWifiPriorityRule(
VcnWifiUnderlyingNetworkTemplate networkPriority,
UnderlyingNetworkRecord networkRecord,
- UnderlyingNetworkRecord currentlySelected,
+ boolean isSelected,
PersistableBundleWrapper carrierConfig) {
final NetworkCapabilities caps = networkRecord.networkCapabilities;
@@ -223,7 +218,7 @@
}
// 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 @@
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 6afa795..3f8d39e 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.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.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 @@
@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 @@
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 @@
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 @@
// 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 @@
.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 @@
*/
@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 @@
@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 @@
@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 @@
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 @@
@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 0000000..2f4cf5e
--- /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 aea9f4d..7ab8e55 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 @@
@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 @@
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 @@
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 073e2d7..eca48b7 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 cd48f5d..106be5f 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 @@
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 05da9df..e5c743c 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 @@
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 @@
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 @@
@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 @@
}
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 @@
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 @@
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 @@
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 4b55bec..676203b 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 @@
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 3a792d0..69fbe6b 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.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.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 @@
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 7af494c..a692167 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.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.window.flags.Flags;
import java.io.File;
+import java.io.PrintWriter;
import java.util.ArrayList;
/**
@@ -136,11 +138,26 @@
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 @@
+ " 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 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 @@
}
}
- 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 @@
}
}
- private static int getSystemHashCode(ActivityRecord activity) {
+ @VisibleForTesting
+ static int getSystemHashCode(ActivityRecord activity) {
return System.identityHashCode(activity);
}
@@ -362,7 +436,13 @@
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 @@
}
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 @@
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 @@
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 @@
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) {
- mUserSavedFiles.get(userId).remove(code);
- mSavedFilesInOrder.remove(usf);
- mPersister.removeSnapshot(code, userId);
+ for (int i = usf.mActivityIds.size() - 1; i >= 0; --i) {
+ final int activityId = usf.mActivityIds.get(i);
+ mCache.onIdRemoved(activityId);
+ }
}
}
- private boolean containsFile(int code, int userId) {
- return getUserFiles(userId).get(code) != null;
+ private void removeIfUserSavedFileExist(ActivityRecord ar) {
+ final UserSavedFile usf = findSavedFile(ar);
+ if (usf != null) {
+ 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(usf.mFileId, ar.mUserId);
+ }
}
- 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
+ boolean hasRecord(@NonNull ActivityRecord ar) {
+ return findSavedFile(ar) != null;
+ }
- if (mSavedFilesInOrder.size() > MAX_PERSIST_SNAPSHOT_COUNT * 2) {
- purgeSavedFile();
- }
+ @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();
}
}
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;
+ }
+
+ 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);
}
- if (usfs.size() > 0) {
- removeSnapshotFiles(usfs);
- }
+ 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 @@
}
}
+ @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 22d17b5..8aaf76a 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 @@
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 @@
return mAnimationTarget;
}
- void createStartingSurface(@NonNull WindowContainer closeWindow) {
+ void createStartingSurface(@NonNull WindowContainer closeWindow,
+ @NonNull ActivityRecord[] visibleOpenActivities) {
if (!mIsOpen) {
return;
}
@@ -1346,7 +1347,7 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 fc3a338..9c9cf04 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 @@
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 @@
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 @@
/*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 @@
/*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 @@
|| 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 @@
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 bf30af3..8035a29 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 @@
* 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 @@
/**
* 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 47972b3..fcc1e5b 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 @@
&& 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 6033220..02b3f15 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 @@
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 ed54ea8..f10a733 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.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 @@
}
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 b6f040a..3014f97 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 @@
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 bffdf54..e4379b5 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 @@
@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 e1bf8f8..f620a97 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 @@
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 @@
}
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 c63cc43..9544835 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.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 @@
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 59d0210..0da0bb4 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 @@
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 @@
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 afb0b20..414339d 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
(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 070bd4b..2ccd1e4 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 69a5e5c..db985fd 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 @@
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 31409ab..b24accb 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 @@
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/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index dfb5a57..fb0729f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -517,6 +517,8 @@
.map(CredentialOption::getType)
.collect(Collectors.toList()));
+ finalizeAndEmitInitialPhaseMetric(session);
+
if (providerSessions.isEmpty()) {
try {
callback.onError(
@@ -776,6 +778,13 @@
providerSessions.forEach(ProviderSession::invokeSession);
}
+ private void finalizeAndEmitInitialPhaseMetric(GetCandidateRequestSession session) {
+ var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric();
+ initMetric.setAutofillSessionId(session.getAutofillSessionId());
+ initMetric.setAutofillRequestId(session.getAutofillRequestId());
+ finalizeAndEmitInitialPhaseMetric((RequestSession) session);
+ }
+
private void finalizeAndEmitInitialPhaseMetric(RequestSession session) {
try {
var initMetric = session.mRequestSessionMetric.getInitialPhaseMetric();
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index d165171..0187ce8 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -49,7 +49,12 @@
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
private static final String TAG = "GetCandidateRequestSession";
+ private static final String SESSION_ID_KEY = "autofill_session_id";
+ private static final String REQUEST_ID_KEY = "autofill_request_id";
+
private final IAutoFillManagerClient mAutoFillCallback;
+ private final int mAutofillSessionId;
+ private final int mAutofillRequestId;
public GetCandidateRequestSession(
Context context, SessionLifetime sessionCallback,
@@ -60,8 +65,13 @@
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());
+ }
}
/**
@@ -137,17 +147,27 @@
@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
@@ -177,4 +197,19 @@
Slog.d(TAG, "onFinalResponseReceived");
respondToClientWithResponseAndFinish(new GetCandidateCredentialsResponse(response));
}
+
+ /**
+ * Returns autofill session id. Returns -1 if unavailable.
+ */
+ public int getAutofillSessionId() {
+ return mAutofillSessionId;
+ }
+
+ /**
+ * Returns autofill request id. Returns -1 if unavailable.
+ */
+ public int getAutofillRequestId() {
+ return mAutofillRequestId;
+
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 3f57c80..49ea19a 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 @@
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/MetricUtilities.java b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
index b36de0b..23aa374 100644
--- a/services/credentials/java/com/android/server/credentials/MetricUtilities.java
+++ b/services/credentials/java/com/android/server/credentials/MetricUtilities.java
@@ -426,7 +426,11 @@
/* per_classtype_counts */
initialPhaseMetric.getUniqueRequestCounts(),
/* origin_specified */
- initialPhaseMetric.isOriginSpecified()
+ initialPhaseMetric.isOriginSpecified(),
+ /* autofill_session_id */
+ initialPhaseMetric.getAutofillSessionId(),
+ /* autofill_request_id */
+ initialPhaseMetric.getAutofillRequestId()
);
} catch (Exception e) {
Slog.w(TAG, "Unexpected error during initial metric emit: " + e);
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index da44aac..67c52e6 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 @@
@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 @@
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/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
index 8e965e3..8a4e86c 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/InitialPhaseMetric.java
@@ -49,6 +49,12 @@
// Stores the deduped request information, particularly {"req":5}
private Map<String, Integer> mRequestCounts = new LinkedHashMap<>();
+ // The session id of autofill if the request is from autofill, defaults to -1
+ private int mAutofillSessionId = -1;
+
+ // The request id of autofill if the request is from autofill, defaults to -1
+ private int mAutofillRequestId = -1;
+
public InitialPhaseMetric(int sessionIdTrackOne) {
mSessionIdCaller = sessionIdTrackOne;
@@ -126,6 +132,24 @@
return mOriginSpecified;
}
+ /* ------ Autofill Integration ------ */
+
+ public void setAutofillSessionId(int autofillSessionId) {
+ mAutofillSessionId = autofillSessionId;
+ }
+
+ public int getAutofillSessionId() {
+ return mAutofillSessionId;
+ }
+
+ public void setAutofillRequestId(int autofillRequestId) {
+ mAutofillRequestId = autofillRequestId;
+ }
+
+ public int getAutofillRequestId() {
+ return mAutofillRequestId;
+ }
+
/* ------ Unique Request Counts Map Information ------ */
public void setRequestCounts(Map<String, Integer> requestCounts) {
diff --git a/services/lint-baseline.xml b/services/lint-baseline.xml
index 8489c17..a311d07 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 1bf031a..11c0cc8e 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/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
index e5be4d9..9e11fa2 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java
@@ -50,7 +50,7 @@
import java.util.Arrays;
import java.util.Collections;
-// atest PackageManagerServiceTest:com.android.server.pm.UserDataPreparerTest
+// atest PackageManagerServiceServerTests:com.android.server.pm.UserDataPreparerTest
@RunWith(AndroidJUnit4.class)
@Presubmit
@SmallTest
@@ -99,7 +99,7 @@
systemDeDir.mkdirs();
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_DE);
verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
- eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
+ eq(StorageManager.FLAG_STORAGE_DE));
verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_DE));
int serialNumber = UserDataPreparer.getSerialNumber(userDeDir);
@@ -116,7 +116,7 @@
systemCeDir.mkdirs();
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
verify(mStorageManagerMock).prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
- eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
+ eq(StorageManager.FLAG_STORAGE_CE));
verify(mInstaller).createUserData(isNull(String.class), eq(TEST_USER_ID),
eq(TEST_USER_SERIAL), eq(StorageManager.FLAG_STORAGE_CE));
int serialNumber = UserDataPreparer.getSerialNumber(userCeDir);
@@ -129,7 +129,7 @@
public void testPrepareUserData_forNewUser_destroysOnFailure() throws Exception {
TEST_USER.lastLoggedInTime = 0;
doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock)
- .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), eq(TEST_USER_SERIAL),
+ .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
verify(mStorageManagerMock).destroyUserStorage(isNull(String.class), eq(TEST_USER_ID),
@@ -140,7 +140,7 @@
public void testPrepareUserData_forExistingUser_doesNotDestroyOnFailure() throws Exception {
TEST_USER.lastLoggedInTime = System.currentTimeMillis();
doThrow(new IllegalStateException("expected exception for test")).when(mStorageManagerMock)
- .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID), eq(TEST_USER_SERIAL),
+ .prepareUserStorage(isNull(String.class), eq(TEST_USER_ID),
eq(StorageManager.FLAG_STORAGE_CE));
mUserDataPreparer.prepareUserData(TEST_USER, StorageManager.FLAG_STORAGE_CE);
verify(mStorageManagerMock, never()).destroyUserStorage(isNull(String.class),
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 4cc68cf..0000000
--- 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 943862f..88a9758 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 @@
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.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.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 @@
private DisplayManagerFlags mDisplayManagerFlagsMock;
@Mock
private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession;
-
@Captor
private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
@@ -165,9 +168,6 @@
.build();
@Rule
- public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule();
-
- @Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Before
@@ -183,10 +183,9 @@
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 @@
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 @@
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 @@
@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 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowers_BothDpcsSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
@@ -363,13 +365,10 @@
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 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
@@ -421,7 +419,6 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
@@ -452,7 +449,6 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() {
DisplayPowerControllerHolder followerDpc =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
@@ -485,7 +481,6 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowers_AutomaticBrightness() {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -557,7 +552,6 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowersRemoval_RemoveSingleFollower() {
DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID,
FOLLOWER_UNIQUE_ID);
@@ -650,7 +644,6 @@
}
@Test
- @FlakyTest(bugId = 294107062)
public void testDisplayBrightnessFollowersRemoval_RemoveAllFollowers() {
DisplayPowerControllerHolder followerHolder =
createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID);
@@ -737,6 +730,82 @@
}
@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 @@
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 @@
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 @@
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 @@
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 @@
}
@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();
- 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.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.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(hdrBrightness), anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), 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.getAutomaticScreenBrightness(
- any(BrightnessEvent.class))).thenReturn(sdrBrightness);
-
- when(mHolder.hbmController.getHighBrightnessMode()).thenReturn(
- BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR);
- when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness);
+ 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).animateTo(eq(hdrBrightness), eq(sdrBrightness),
- eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false));
+ verify(mHolder.animator, atLeastOnce()).animateTo(eq(clampedBrightness), anyFloat(),
+ eq(transitionRate), eq(true));
+ }
- when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(hdrBrightness);
- when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness);
- when(mHolder.hbmController.getHighBrightnessMode()).thenReturn(
- BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
+ @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());
- clearInvocations(mHolder.animator);
-
- 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(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
@@ -1285,14 +1377,14 @@
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 @@
@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 @@
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 @@
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 @@
// 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 @@
@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 @@
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 @@
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 @@
.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 @@
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());
- DisplayPowerController.Injector injector = spy(new TestInjector(displayPowerState, animator,
- automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels,
- screenOffBrightnessSensorController, hbmController));
+ 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 @@
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 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 @@
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 @@
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 @@
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 @@
}
@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 @@
}
@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 5c50acb..a8af98f 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 @@
@Test
public void testFindHighestRefreshRateForDefaultDisplay() {
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ assertEquals(120,
+ RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
+ /* delta= */ 0);
+ }
+
+ @Test
+ public void testFindHighestRefreshRate_DisplayIsNull() {
when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
assertEquals(DEFAULT_REFRESH_RATE,
RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
/* delta= */ 0);
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
- assertEquals(120,
- 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 a0e5fd8..83479e2 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_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 @@
};
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 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 @@
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 @@
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 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 @@
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 @@
@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/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index e4b6206..d876dae 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -101,6 +101,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import android.util.SparseArray;
@@ -111,7 +112,9 @@
import org.junit.After;
import org.junit.AfterClass;
+import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
import java.io.File;
@@ -161,6 +164,9 @@
private static PackageManagerInternal sPackageManagerInternal;
private static ActivityManagerService sService;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@SuppressWarnings("GuardedBy")
@BeforeClass
public static void setUpOnce() {
@@ -227,6 +233,11 @@
}
}
+ @Before
+ public void setUp() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_NEW_FGS_RESTRICTION_LOGIC);
+ }
+
@AfterClass
public static void tearDownOnce() {
LocalServices.removeServiceForTest(PackageManagerInternal.class);
@@ -540,6 +551,7 @@
sService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
@@ -582,6 +594,7 @@
// SHORT_SERVICE, timed out already.
s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
@@ -1100,6 +1113,7 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
@@ -1130,6 +1144,7 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
@@ -1421,6 +1436,7 @@
// In order to trick OomAdjuster to think it has a short-service, we need this logic.
ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+ s.appInfo = new ApplicationInfo();
s.startRequested = true;
s.isForeground = true;
s.foregroundServiceType = FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
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 fc2e5b0..0703db2 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 @@
@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/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 97e94e3..37ca09d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -47,7 +47,6 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricManager;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -280,7 +279,7 @@
"com.android/.SystemTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ true);
- mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
+ notifyPackageChanged(newAgentComponentName);
assertThat(mEnabledTrustAgents).containsExactly(newAgentComponentName);
assertThat(mKnownTrustAgents).containsExactly(newAgentComponentName);
@@ -299,7 +298,7 @@
"com.android/.SystemTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ true);
- mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
+ notifyPackageChanged(newAgentComponentName);
assertThat(mEnabledTrustAgents).containsExactly(defaultTrustAgent);
assertThat(mKnownTrustAgents).containsExactly(defaultTrustAgent, newAgentComponentName);
@@ -312,7 +311,7 @@
"com.user/.UserTrustAgent");
addTrustAgent(newAgentComponentName, /* isSystemApp= */ false);
- mMockContext.sendPackageChangedBroadcast(newAgentComponentName);
+ notifyPackageChanged(newAgentComponentName);
assertThat(mEnabledTrustAgents).isEmpty();
assertThat(mKnownTrustAgents).containsExactly(newAgentComponentName);
@@ -330,7 +329,7 @@
// Simulate user turning off systemTrustAgent2
mLockPatternUtils.setEnabledTrustAgents(List.of(systemTrustAgent1), TEST_USER_ID);
- mMockContext.sendPackageChangedBroadcast(systemTrustAgent2);
+ notifyPackageChanged(systemTrustAgent2);
assertThat(mEnabledTrustAgents).containsExactly(systemTrustAgent1);
}
@@ -440,11 +439,16 @@
permission, PackageManager.PERMISSION_GRANTED);
}
+ private void notifyPackageChanged(ComponentName changedComponent) {
+ mService.mPackageMonitor.onPackageChanged(
+ changedComponent.getPackageName(),
+ UserHandle.of(TEST_USER_ID).getUid(1234),
+ new String[] { changedComponent.getClassName() });
+ }
+
/** A mock Context that allows the test process to send protected broadcasts. */
private static final class MockContext extends TestableContext {
- private final ArrayList<BroadcastReceiver> mPackageChangedBroadcastReceivers =
- new ArrayList<>();
private final ArrayList<BroadcastReceiver> mUserStartedBroadcastReceivers =
new ArrayList<>();
@@ -458,9 +462,6 @@
UserHandle user, IntentFilter filter, @Nullable String broadcastPermission,
@Nullable Handler scheduler) {
- if (filter.hasAction(Intent.ACTION_PACKAGE_CHANGED)) {
- mPackageChangedBroadcastReceivers.add(receiver);
- }
if (filter.hasAction(Intent.ACTION_USER_STARTED)) {
mUserStartedBroadcastReceivers.add(receiver);
}
@@ -473,20 +474,6 @@
@Nullable String receiverPermission, @Nullable Bundle options) {
}
- void sendPackageChangedBroadcast(ComponentName changedComponent) {
- Intent intent = new Intent(
- Intent.ACTION_PACKAGE_CHANGED,
- Uri.fromParts(URI_SCHEME_PACKAGE,
- changedComponent.getPackageName(), /* fragment= */ null))
- .putExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST,
- new String[]{changedComponent.getClassName()})
- .putExtra(Intent.EXTRA_USER_HANDLE, TEST_USER_ID)
- .putExtra(Intent.EXTRA_UID, UserHandle.of(TEST_USER_ID).getUid(1234));
- for (BroadcastReceiver receiver : mPackageChangedBroadcastReceivers) {
- receiver.onReceive(this, intent);
- }
- }
-
void sendUserStartedBroadcast() {
Intent intent = new Intent(Intent.ACTION_USER_STARTED)
.putExtra(Intent.EXTRA_USER_HANDLE, TEST_USER_ID);
diff --git a/services/tests/powerstatstests/Android.bp b/services/tests/powerstatstests/Android.bp
index 05e0e8f..654d7a8d 100644
--- a/services/tests/powerstatstests/Android.bp
+++ b/services/tests/powerstatstests/Android.bp
@@ -11,6 +11,7 @@
"src/com/android/server/power/stats/MultiStateStatsTest.java",
"src/com/android/server/power/stats/PowerStatsAggregatorTest.java",
"src/com/android/server/power/stats/PowerStatsCollectorTest.java",
+ "src/com/android/server/power/stats/PowerStatsExporterTest.java",
"src/com/android/server/power/stats/PowerStatsSchedulerTest.java",
"src/com/android/server/power/stats/PowerStatsStoreTest.java",
"src/com/android/server/power/stats/PowerStatsUidResolverTest.java",
@@ -83,6 +84,9 @@
],
srcs: [
":power_stats_ravenwood_tests",
+
+ "src/com/android/server/power/stats/BatteryUsageStatsRule.java",
+ "src/com/android/server/power/stats/MockBatteryStatsImpl.java",
"src/com/android/server/power/stats/MockClock.java",
],
auto_gen_config: true,
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
index 4ea0805..3f058a2 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryChargeCalculatorTest.java
@@ -37,12 +37,12 @@
private static final double PRECISION = 0.00001;
@Rule
- public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule();
+ public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
+ .setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0);
@Test
public void testDischargeTotals() {
// Nominal battery capacity should be ignored
- mStatsRule.setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 1234.0);
final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
@@ -84,8 +84,6 @@
@Test
public void testDischargeTotals_chargeUahUnavailable() {
- mStatsRule.setAveragePower(PowerProfile.POWER_BATTERY_CAPACITY, 4000.0);
-
final BatteryStatsImpl batteryStats = mStatsRule.getBatteryStats();
batteryStats.setBatteryStateLocked(BatteryManager.BATTERY_STATUS_DISCHARGING, 100,
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index e61dd0b..ca162e0 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -18,11 +18,11 @@
import static org.mockito.ArgumentMatchers.anyDouble;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.annotation.XmlRes;
-import android.content.Context;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
import android.os.BatteryStats;
@@ -54,12 +54,11 @@
.powerProfileModeledOnly()
.includePowerModels()
.build();
- private final Context mContext;
private final PowerProfile mPowerProfile;
private final MockClock mMockClock = new MockClock();
private final MockBatteryStatsImpl mBatteryStats;
- private final Handler mHandler;
+ private Handler mHandler;
private BatteryUsageStats mBatteryUsageStats;
private boolean mScreenOn;
@@ -76,11 +75,8 @@
}
public BatteryUsageStatsRule(long currentTime, File historyDir) {
- HandlerThread bgThread = new HandlerThread("bg thread");
- bgThread.start();
- mHandler = new Handler(bgThread.getLooper());
- mContext = InstrumentationRegistry.getContext();
- mPowerProfile = spy(new PowerProfile(mContext, true /* forTest */));
+ mHandler = mock(Handler.class);
+ mPowerProfile = spy(new PowerProfile());
mMockClock.currentTime = currentTime;
mBatteryStats = new MockBatteryStatsImpl(mMockClock, historyDir, mHandler);
mBatteryStats.setPowerProfile(mPowerProfile);
@@ -103,7 +99,7 @@
}
public BatteryUsageStatsRule setTestPowerProfile(@XmlRes int xmlId) {
- mPowerProfile.forceInitForTesting(mContext, xmlId);
+ mPowerProfile.forceInitForTesting(InstrumentationRegistry.getContext(), xmlId);
return this;
}
@@ -222,13 +218,17 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- noteOnBattery();
+ before();
base.evaluate();
}
};
}
- private void noteOnBattery() {
+ private void before() {
+ HandlerThread bgThread = new HandlerThread("bg thread");
+ bgThread.start();
+ mHandler = new Handler(bgThread.getLooper());
+ mBatteryStats.setHandler(mHandler);
mBatteryStats.setOnBatteryInternal(true);
mBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
mBatteryStats.getOnBatteryScreenOffTimeBase().setRunning(!mScreenOn, 0, 0);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
index fb71ac8..78c4bac 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/MockBatteryStatsImpl.java
@@ -271,6 +271,10 @@
public void writeSyncLocked() {
}
+ public void setHandler(Handler handler) {
+ mHandler = handler;
+ }
+
public static class DummyExternalStatsSync implements ExternalStatsSync {
public int flags = 0;
@@ -315,4 +319,3 @@
}
}
}
-
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
index 3c48262..3560a26 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsExporterTest.java
@@ -16,8 +16,6 @@
package com.android.server.power.stats;
-import static androidx.test.InstrumentationRegistry.getContext;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -34,6 +32,7 @@
import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.UidBatteryConsumer;
+import android.platform.test.ravenwood.RavenwoodRule;
import androidx.test.runner.AndroidJUnit4;
@@ -48,6 +47,8 @@
import org.junit.runner.RunWith;
import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
import java.util.List;
@RunWith(AndroidJUnit4.class)
@@ -57,7 +58,12 @@
private static final int APP_UID2 = 84;
private static final double TOLERANCE = 0.01;
- @Rule
+ @Rule(order = 0)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Rule(order = 1)
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
.setAveragePower(PowerProfile.POWER_CPU_ACTIVE, 720)
.setCpuScalingPolicy(0, new int[]{0}, new int[]{100})
@@ -75,8 +81,8 @@
private PowerStats.Descriptor mPowerStatsDescriptor;
@Before
- public void setup() {
- File storeDirectory = new File(getContext().getCacheDir(), getClass().getSimpleName());
+ public void setup() throws IOException {
+ File storeDirectory = Files.createTempDirectory("PowerStatsExporterTest").toFile();
clearDirectory(storeDirectory);
AggregatedPowerStatsConfig config = new AggregatedPowerStatsConfig();
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 c0051c6..eee3752 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 @@
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 feb6bd9..467c15d 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 @@
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/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index 77b1455..26934d8 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -763,8 +763,7 @@
mUserController.startUser(TEST_USER_ID, USER_START_MODE_BACKGROUND);
- verify(mInjector.mStorageManagerMock, never())
- .unlockCeStorage(eq(TEST_USER_ID), anyInt(), any());
+ verify(mInjector.mStorageManagerMock, never()).unlockCeStorage(eq(TEST_USER_ID), any());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 8929900..f7480de 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -44,12 +44,18 @@
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.fingerprint.IFingerprint;
+import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.Fingerprint;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper;
@@ -60,6 +66,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.nano.BiometricSchedulerProto;
@@ -95,14 +102,39 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getContext(), null);
- private BiometricScheduler mScheduler;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+ private BiometricScheduler<IFingerprint, ISession> mScheduler;
private IBinder mToken;
+ private int mCurrentUserId = UserHandle.USER_SYSTEM;
+ private boolean mShouldFailStopUser = false;
+ private final List<Integer> mStartedUsers = new ArrayList<>();
+ private final StartUserClient.UserStartedCallback<ISession> mUserStartedCallback =
+ (newUserId, newUser, halInterfaceVersion) -> {
+ mStartedUsers.add(newUserId);
+ mCurrentUserId = newUserId;
+ };
+ private int mUsersStoppedCount = 0;
+ private final StopUserClient.UserStoppedCallback mUserStoppedCallback =
+ () -> {
+ mUsersStoppedCount++;
+ mCurrentUserId = UserHandle.USER_NULL;
+ };
+ private boolean mStartOperationsFinish = true;
+ private int mStartUserClientCount = 0;
@Mock
private IBiometricService mBiometricService;
@Mock
private BiometricContext mBiometricContext;
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
+ @Mock
+ private BiometricLogger mBiometricLogger;
+ @Mock
+ private ISession mSession;
+ @Mock
+ private IFingerprint mFingerprint;
@Before
public void setUp() {
@@ -111,9 +143,39 @@
when(mAuthSessionCoordinator.getLockoutStateFor(anyInt(), anyInt())).thenReturn(
BIOMETRIC_SUCCESS);
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
- mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()),
- BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
- mBiometricService, LOG_NUM_RECENT_OPERATIONS);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(TestableLooper.get(this).getLooper()),
+ BiometricScheduler.SENSOR_TYPE_UNKNOWN,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ LOG_NUM_RECENT_OPERATIONS,
+ () -> mCurrentUserId,
+ new UserSwitchProvider<IFingerprint, ISession>() {
+ @NonNull
+ @Override
+ public StopUserClient<ISession> getStopUserClient(int userId) {
+ return new TestStopUserClient(mContext, () -> mSession, mToken, userId,
+ TEST_SENSOR_ID, mBiometricLogger, mBiometricContext,
+ mUserStoppedCallback, () -> mShouldFailStopUser);
+ }
+
+ @NonNull
+ @Override
+ public StartUserClient<IFingerprint, ISession> getStartUserClient(
+ int newUserId) {
+ mStartUserClientCount++;
+ return new TestStartUserClient(mContext, () -> mFingerprint, mToken,
+ newUserId, TEST_SENSOR_ID, mBiometricLogger, mBiometricContext,
+ mUserStartedCallback, mStartOperationsFinish);
+ }
+ });
+ } else {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(TestableLooper.get(this).getLooper()),
+ BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
+ mBiometricService, LOG_NUM_RECENT_OPERATIONS);
+ }
}
@Test
@@ -479,6 +541,7 @@
final boolean isEnroll = client instanceof TestEnrollClient;
mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
if (started) {
mScheduler.startPreparedClient(client.getCookie());
}
@@ -789,6 +852,172 @@
assertEquals(1, client1.getFingerprints().size());
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ final BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(0);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+ waitForIdle();
+
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).containsExactly(0);
+ verify(nextClient).start(any());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser_notStarted() {
+ mCurrentUserId = UserHandle.USER_NULL;
+ mStartOperationsFinish = false;
+
+ final BaseClientMonitor[] nextClients = new BaseClientMonitor[]{
+ mock(BaseClientMonitor.class),
+ mock(BaseClientMonitor.class),
+ mock(BaseClientMonitor.class)
+ };
+ for (BaseClientMonitor client : nextClients) {
+ when(client.getTargetUserId()).thenReturn(5);
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+ }
+
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).isEmpty();
+ assertThat(mStartUserClientCount).isEqualTo(1);
+ for (BaseClientMonitor client : nextClients) {
+ verify(client, never()).start(any());
+ }
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenNoUser_notStarted_andReset() {
+ mCurrentUserId = UserHandle.USER_NULL;
+ mStartOperationsFinish = false;
+
+ final BaseClientMonitor client = mock(BaseClientMonitor.class);
+
+ when(client.getTargetUserId()).thenReturn(5);
+
+ mScheduler.scheduleClientMonitor(client);
+ waitForIdle();
+
+ final TestStartUserClient startUserClient =
+ (TestStartUserClient) mScheduler.mCurrentOperation.getClientMonitor();
+ mScheduler.reset();
+
+ assertThat(mScheduler.mCurrentOperation).isNull();
+
+ final BiometricSchedulerOperation fakeOperation = new BiometricSchedulerOperation(
+ mock(BaseClientMonitor.class), new ClientMonitorCallback() {});
+ mScheduler.mCurrentOperation = fakeOperation;
+ startUserClient.mCallback.onClientFinished(startUserClient, true);
+
+ assertThat(fakeOperation).isSameInstanceAs(mScheduler.mCurrentOperation);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenSameUser() {
+ mCurrentUserId = 10;
+
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(mCurrentUserId);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+
+ verify(nextClient).start(any());
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mStartedUsers).isEmpty();
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testScheduleOperation_whenDifferentUser() {
+ mCurrentUserId = 10;
+
+ final int nextUserId = 11;
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(nextUserId);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ assertThat(mUsersStoppedCount).isEqualTo(1);
+
+ waitForIdle();
+ assertThat(mStartedUsers).containsExactly(nextUserId);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testStartUser_alwaysStartsNextOperation() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+ assertThat(mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUsersStoppedCount).isEqualTo(1);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void testStartUser_failsClearsStopUserClient() {
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ // When a stop user client fails, check that mStopUserClient
+ // is set to null to prevent the scheduler from getting stuck.
+ BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(10);
+
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ verify(nextClient).start(any());
+
+ // finish first operation
+ mScheduler.getInternalCallback().onClientFinished(nextClient, true /* success */);
+ waitForIdle();
+
+ // schedule second operation but swap out the current operation
+ // before it runs so that it's not current when it's completion callback runs
+ nextClient = mock(BaseClientMonitor.class);
+ when(nextClient.getTargetUserId()).thenReturn(11);
+ mShouldFailStopUser = true;
+ mScheduler.scheduleClientMonitor(nextClient);
+
+ waitForIdle();
+ assertThat(mStartedUsers).containsExactly(10, 11).inOrder();
+ assertThat(mUsersStoppedCount).isEqualTo(0);
+ assertThat(mScheduler.getStopUserClient()).isEqualTo(null);
+ }
private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
@@ -1069,4 +1298,82 @@
return mFingerprints;
}
}
+
+ private interface StopUserClientShouldFail {
+ boolean shouldFail();
+ }
+
+ private class TestStopUserClient extends StopUserClient<ISession> {
+ private StopUserClientShouldFail mShouldFailClient;
+ TestStopUserClient(@NonNull Context context,
+ @NonNull Supplier<ISession> lazyDaemon, @Nullable IBinder token, int userId,
+ int sensorId, @NonNull BiometricLogger logger,
+ @NonNull BiometricContext biometricContext,
+ @NonNull UserStoppedCallback callback, StopUserClientShouldFail shouldFail) {
+ super(context, lazyDaemon, token, userId, sensorId, logger, biometricContext, callback);
+ mShouldFailClient = shouldFail;
+ }
+
+ @Override
+ protected void startHalOperation() {
+
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+ if (mShouldFailClient.shouldFail()) {
+ getCallback().onClientFinished(this, false /* success */);
+ // When the above fails, it means that the HAL has died, in this case we
+ // need to ensure the UserSwitchCallback correctly returns the NULL user handle.
+ mCurrentUserId = UserHandle.USER_NULL;
+ } else {
+ onUserStopped();
+ }
+ }
+
+ @Override
+ public void unableToStart() {
+
+ }
+ }
+
+ private static class TestStartUserClient extends StartUserClient<IFingerprint, ISession> {
+
+ @Mock
+ private ISession mSession;
+ private final boolean mShouldFinish;
+ ClientMonitorCallback mCallback;
+
+ TestStartUserClient(@NonNull Context context,
+ @NonNull Supplier<IFingerprint> lazyDaemon, @Nullable IBinder token, int userId,
+ int sensorId, @NonNull BiometricLogger logger,
+ @NonNull BiometricContext biometricContext,
+ @NonNull UserStartedCallback<ISession> callback, boolean shouldFinish) {
+ super(context, lazyDaemon, token, userId, sensorId, logger, biometricContext, callback);
+ mShouldFinish = shouldFinish;
+ }
+
+ @Override
+ protected void startHalOperation() {
+
+ }
+
+ @Override
+ public void start(@NonNull ClientMonitorCallback callback) {
+ super.start(callback);
+
+ mCallback = callback;
+ if (mShouldFinish) {
+ mUserStartedCallback.onUserStarted(
+ getTargetUserId(), mSession, 1 /* halInterfaceVersion */);
+ callback.onClientFinished(this, true /* success */);
+ }
+ }
+
+ @Override
+ public void unableToStart() {
+
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
index 8b1a291..772ec8b 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceProviderTest.java
@@ -36,8 +36,10 @@
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.HidlFaceSensorConfig;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -88,14 +90,11 @@
@Mock
private BiometricStateCallback mBiometricStateCallback;
+ private final TestLooper mLooper = new TestLooper();
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
private FaceProvider mFaceProvider;
- private static void waitForIdle() {
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -121,7 +120,8 @@
mFaceProvider = new FaceProvider(mContext, mBiometricStateCallback,
mSensorProps, TAG, mLockoutResetDispatcher, mBiometricContext,
- mDaemon, false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */);
+ mDaemon, new Handler(mLooper.getLooper()),
+ false /* resetLockoutRequiresChallenge */, false /* testHalEnabled */);
}
@Test
@@ -156,6 +156,7 @@
mFaceProvider = new FaceProvider(mContext,
mBiometricStateCallback, hidlFaceSensorConfig, TAG,
mLockoutResetDispatcher, mBiometricContext, mDaemon,
+ new Handler(mLooper.getLooper()),
true /* resetLockoutRequiresChallenge */,
true /* testHalEnabled */);
@@ -210,4 +211,12 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
+
+ private void waitForIdle() {
+ if (Flags.deHidl()) {
+ mLooper.dispatchAll();
+ } else {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index e7f7195..fe9cd43 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -31,6 +31,7 @@
import android.content.Context;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.face.FaceSensorPropertiesInternal;
@@ -40,6 +41,7 @@
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
@@ -49,6 +51,7 @@
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import org.junit.Before;
import org.junit.Test;
@@ -74,6 +77,8 @@
@Mock
private UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback;
@Mock
+ private UserSwitchProvider<IFace, ISession> mUserSwitchProvider;
+ @Mock
private AidlResponseHandler.HardwareUnavailableCallback mHardwareUnavailableCallback;
@Mock
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -84,16 +89,16 @@
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
@Mock
- FaceProvider mFaceProvider;
+ private FaceProvider mFaceProvider;
@Mock
- BaseClientMonitor mClientMonitor;
+ private BaseClientMonitor mClientMonitor;
@Mock
- AidlSession mCurrentSession;
+ private AidlSession mCurrentSession;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
- private UserAwareBiometricScheduler mScheduler;
+ private BiometricScheduler<IFace, ISession> mScheduler;
private AidlResponseHandler mHalCallback;
@Before
@@ -101,16 +106,26 @@
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
-
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
- mScheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ 2 /* recentOperationsLimit */,
+ () -> USER_ID,
+ mUserSwitchProvider);
+ } else {
+ mScheduler = new UserAwareBiometricScheduler<>(TAG,
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FACE,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ () -> USER_ID,
+ mUserSwitchCallback);
+ }
mHalCallback = new AidlResponseHandler(mContext, mScheduler, SENSOR_ID, USER_ID,
mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
mHardwareUnavailableCallback);
@@ -146,18 +161,8 @@
@Test
public void onBinderDied_noErrorOnNullClient() {
mLooper.dispatchAll();
-
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
- sensorProps.sensorType, sensorProps.supportsDetectInteraction,
- sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext,
- null /* handler */, internalProp, mLockoutResetDispatcher, mBiometricContext);
- sensor.init(mLockoutResetDispatcher, mFaceProvider);
+ final Sensor sensor = getSensor();
+ mScheduler = sensor.getScheduler();
mScheduler.reset();
assertNull(mScheduler.getCurrentClient());
@@ -175,18 +180,8 @@
when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
when(mClientMonitor.isInterruptable()).thenReturn(false);
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
- sensorProps.sensorType, sensorProps.supportsDetectInteraction,
- sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
- final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext, null,
- internalProp, mLockoutResetDispatcher, mBiometricContext, mCurrentSession);
- sensor.init(mLockoutResetDispatcher, mFaceProvider);
- mScheduler = (UserAwareBiometricScheduler) sensor.getScheduler();
+ final Sensor sensor = getSensor();
+ mScheduler = sensor.getScheduler();
sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
USER_ID, mHalCallback);
@@ -206,4 +201,20 @@
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
+
+ private Sensor getSensor() {
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null /* componentInfo */,
+ sensorProps.sensorType, sensorProps.supportsDetectInteraction,
+ sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+ final Sensor sensor = new Sensor(mFaceProvider, mContext,
+ null /* handler */, internalProp, mBiometricContext);
+ sensor.init(mLockoutResetDispatcher, mFaceProvider);
+
+ return sensor;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
index 4e43332..940fe69 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/HidlToAidlSensorAdapterTest.java
@@ -45,7 +45,6 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
-import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
@@ -88,9 +87,9 @@
@Mock
private IBiometricsFace mDaemon;
@Mock
- AidlResponseHandler.AidlResponseHandlerCallback mAidlResponseHandlerCallback;
+ private AidlResponseHandler.AidlResponseHandlerCallback mAidlResponseHandlerCallback;
@Mock
- BiometricUtils<Face> mBiometricUtils;
+ private BiometricUtils<Face> mBiometricUtils;
private final TestLooper mLooper = new TestLooper();
private HidlToAidlSensorAdapter mHidlToAidlSensorAdapter;
@@ -118,20 +117,14 @@
mContext.getOrCreateTestableResources();
final String config = String.format("%d:8:15", SENSOR_ID);
- final BiometricScheduler scheduler = new BiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FACE,
- null /* gestureAvailabilityTracker */,
- mBiometricService, 10 /* recentOperationsLimit */);
final HidlFaceSensorConfig faceSensorConfig = new HidlFaceSensorConfig();
faceSensorConfig.parse(config, mContext);
- mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(TAG, mFaceProvider,
+ mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(mFaceProvider,
mContext, new Handler(mLooper.getLooper()), faceSensorConfig,
mLockoutResetDispatcherForSensor, mBiometricContext,
false /* resetLockoutRequiresChallenge */, mInternalCleanupAndGetFeatureRunnable,
mAuthSessionCoordinator, mDaemon, mAidlResponseHandlerCallback);
mHidlToAidlSensorAdapter.init(mLockoutResetDispatcherForSensor, mFaceProvider);
- mHidlToAidlSensorAdapter.setScheduler(scheduler);
mHidlToAidlSensorAdapter.handleUserChanged(USER_ID);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index bf5986c..258be57 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -38,8 +38,10 @@
import android.hardware.biometrics.fingerprint.SensorLocation;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.HidlFingerprintSensorConfig;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
@@ -92,14 +94,12 @@
@Mock
private BiometricContext mBiometricContext;
+ private final TestLooper mLooper = new TestLooper();
+
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
private FingerprintProvider mFingerprintProvider;
- private static void waitForIdle() {
- InstrumentationRegistry.getInstrumentation().waitForIdleSync();
- }
-
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
@@ -126,7 +126,8 @@
mFingerprintProvider = new FingerprintProvider(mContext,
mBiometricStateCallback, mAuthenticationStateListeners, mSensorProps, TAG,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher, mBiometricContext,
- mDaemon, false /* resetLockoutRequiresHardwareAuthToken */,
+ mDaemon, new Handler(mLooper.getLooper()),
+ false /* resetLockoutRequiresHardwareAuthToken */,
true /* testHalEnabled */);
}
@@ -159,6 +160,7 @@
mBiometricStateCallback, mAuthenticationStateListeners,
hidlFingerprintSensorConfigs, TAG, mLockoutResetDispatcher,
mGestureAvailabilityDispatcher, mBiometricContext, mDaemon,
+ new Handler(mLooper.getLooper()),
false /* resetLockoutRequiresHardwareAuthToken */,
true /* testHalEnabled */);
@@ -215,4 +217,12 @@
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
+
+ private void waitForIdle() {
+ if (Flags.deHidl()) {
+ mLooper.dispatchAll();
+ } else {
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index 126a05e..b4c2ee8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -32,14 +32,17 @@
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.face.SensorProps;
+import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
@@ -49,6 +52,7 @@
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.UserSwitchProvider;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
@@ -75,6 +79,8 @@
@Mock
private UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback;
@Mock
+ private UserSwitchProvider<IFingerprint, ISession> mUserSwitchProvider;
+ @Mock
private AidlResponseHandler.HardwareUnavailableCallback mHardwareUnavailableCallback;
@Mock
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -92,11 +98,13 @@
private AidlSession mCurrentSession;
@Mock
private BaseClientMonitor mClientMonitor;
+ @Mock
+ private HandlerThread mThread;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
- private BiometricScheduler mScheduler;
+ private BiometricScheduler<IFingerprint, ISession> mScheduler;
private AidlResponseHandler mHalCallback;
@Before
@@ -105,14 +113,26 @@
when(mContext.getSystemService(Context.BIOMETRIC_SERVICE)).thenReturn(mBiometricService);
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
+ when(mThread.getLooper()).thenReturn(mLooper.getLooper());
- mScheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FP_OTHER,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
+ if (Flags.deHidl()) {
+ mScheduler = new BiometricScheduler<>(
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FP_OTHER,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ 2 /* recentOperationsLimit */,
+ () -> USER_ID,
+ mUserSwitchProvider);
+ } else {
+ mScheduler = new UserAwareBiometricScheduler<>(TAG,
+ new Handler(mLooper.getLooper()),
+ BiometricScheduler.SENSOR_TYPE_FP_OTHER,
+ null /* gestureAvailabilityDispatcher */,
+ mBiometricService,
+ () -> USER_ID,
+ mUserSwitchCallback);
+ }
mHalCallback = new AidlResponseHandler(mContext, mScheduler, SENSOR_ID, USER_ID,
mLockoutCache, mLockoutResetDispatcher, mAuthSessionCoordinator,
mHardwareUnavailableCallback);
@@ -153,18 +173,7 @@
when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
when(mClientMonitor.isInterruptable()).thenReturn(false);
- final SensorProps sensorProps = new SensorProps();
- sensorProps.commonProps = new CommonProps();
- sensorProps.commonProps.sensorId = 1;
- final FingerprintSensorPropertiesInternal internalProp = new
- FingerprintSensorPropertiesInternal(
- sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
- sensorProps.commonProps.maxEnrollmentsPerUser, null,
- sensorProps.sensorType, false /* resetLockoutRequiresHardwareAuthToken */);
- final Sensor sensor = new Sensor("SensorTest", mFingerprintProvider, mContext,
- null /* handler */, internalProp, mLockoutResetDispatcher,
- mGestureAvailabilityDispatcher, mBiometricContext, mCurrentSession);
- sensor.init(mGestureAvailabilityDispatcher, mLockoutResetDispatcher);
+ final Sensor sensor = getSensor();
mScheduler = sensor.getScheduler();
sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
USER_ID, mHalCallback);
@@ -185,4 +194,21 @@
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
verify(mAuthSessionCoordinator).resetLockoutFor(eq(USER_ID), anyInt(), anyLong());
}
+
+ private Sensor getSensor() {
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FingerprintSensorPropertiesInternal internalProp = new
+ FingerprintSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null,
+ sensorProps.sensorType, false /* resetLockoutRequiresHardwareAuthToken */);
+ final Sensor sensor = new Sensor(mFingerprintProvider, mContext,
+ null /* handler */, internalProp,
+ mBiometricContext, mCurrentSession);
+ sensor.init(mGestureAvailabilityDispatcher, mLockoutResetDispatcher);
+
+ return sensor;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
index 89a4961..cbbc545 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/HidlToAidlSensorAdapterTest.java
@@ -36,12 +36,12 @@
import android.hardware.fingerprint.Fingerprint;
import android.hardware.fingerprint.HidlFingerprintSensorConfig;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
-import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
@@ -49,17 +49,11 @@
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
import com.android.server.biometrics.sensors.AuthenticationStateListeners;
-import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.BiometricUtils;
-import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.StartUserClient;
-import com.android.server.biometrics.sensors.StopUserClient;
-import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import com.android.server.biometrics.sensors.fingerprint.aidl.AidlResponseHandler;
-import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintEnrollClient;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintResetLockoutClient;
@@ -111,60 +105,18 @@
private BiometricUtils<Fingerprint> mBiometricUtils;
@Mock
private AuthenticationStateListeners mAuthenticationStateListeners;
+ @Mock
+ private HandlerThread mThread;
private final TestLooper mLooper = new TestLooper();
private HidlToAidlSensorAdapter mHidlToAidlSensorAdapter;
private final TestableContext mContext = new TestableContext(
ApplicationProvider.getApplicationContext());
- private final UserAwareBiometricScheduler.UserSwitchCallback mUserSwitchCallback =
- new UserAwareBiometricScheduler.UserSwitchCallback() {
- @NonNull
- @Override
- public StopUserClient<?> getStopUserClient(int userId) {
- return new StopUserClient<IBiometricsFingerprint>(mContext,
- mHidlToAidlSensorAdapter::getIBiometricsFingerprint, null, USER_ID,
- SENSOR_ID, mLogger, mBiometricContext, () -> {}) {
- @Override
- protected void startHalOperation() {
- getCallback().onClientFinished(this, true /* success */);
- }
-
- @Override
- public void unableToStart() {}
- };
- }
-
- @NonNull
- @Override
- public StartUserClient<?, ?> getStartUserClient(int newUserId) {
- return new StartUserClient<IBiometricsFingerprint, AidlSession>(mContext,
- mHidlToAidlSensorAdapter::getIBiometricsFingerprint, null,
- USER_ID, SENSOR_ID,
- mLogger, mBiometricContext,
- (newUserId1, newUser, halInterfaceVersion) ->
- mHidlToAidlSensorAdapter.handleUserChanged(newUserId1)) {
- @Override
- public void start(@NonNull ClientMonitorCallback callback) {
- super.start(callback);
- startHalOperation();
- }
-
- @Override
- protected void startHalOperation() {
- mUserStartedCallback.onUserStarted(USER_ID, null, 0);
- getCallback().onClientFinished(this, true /* success */);
- }
-
- @Override
- public void unableToStart() {}
- };
- }
- };;
-
@Before
public void setUp() throws RemoteException {
when(mBiometricContext.getAuthSessionCoordinator()).thenReturn(mAuthSessionCoordinator);
+ when(mThread.getLooper()).thenReturn(mLooper.getLooper());
doAnswer((answer) -> {
mHidlToAidlSensorAdapter.getLazySession().get().getHalSessionCallback()
.onEnrollmentProgress(1 /* enrollmentId */, 0 /* remaining */);
@@ -175,26 +127,18 @@
mContext.getOrCreateTestableResources();
final String config = String.format("%d:2:15", SENSOR_ID);
- final UserAwareBiometricScheduler scheduler = new UserAwareBiometricScheduler(TAG,
- new Handler(mLooper.getLooper()),
- BiometricScheduler.SENSOR_TYPE_FP_OTHER,
- null /* gestureAvailabilityDispatcher */,
- mBiometricService,
- () -> USER_ID,
- mUserSwitchCallback);
final HidlFingerprintSensorConfig fingerprintSensorConfig =
new HidlFingerprintSensorConfig();
fingerprintSensorConfig.parse(config, mContext);
- mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(TAG,
+ mHidlToAidlSensorAdapter = new HidlToAidlSensorAdapter(
mFingerprintProvider, mContext, new Handler(mLooper.getLooper()),
fingerprintSensorConfig, mLockoutResetDispatcherForSensor,
- mGestureAvailabilityDispatcher, mBiometricContext,
- false /* resetLockoutRequiresHardwareAuthToken */,
+ mBiometricContext, false /* resetLockoutRequiresHardwareAuthToken */,
mInternalCleanupRunnable, mAuthSessionCoordinator, mDaemon,
mAidlResponseHandlerCallback);
mHidlToAidlSensorAdapter.init(mGestureAvailabilityDispatcher,
mLockoutResetDispatcherForSensor);
- mHidlToAidlSensorAdapter.setScheduler(scheduler);
+
mHidlToAidlSensorAdapter.handleUserChanged(USER_ID);
}
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 276c832..e1f490a 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 @@
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 6b85a32..95a9610 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.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 @@
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/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index f5d50d1..6986cab 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -305,9 +305,9 @@
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
mStorageManager.unlockCeStorage(/* userId= */ (int) args[0],
- /* secret= */ (byte[]) args[2]);
+ /* secret= */ (byte[]) args[1]);
return null;
- }).when(sm).unlockCeStorage(anyInt(), anyInt(), any());
+ }).when(sm).unlockCeStorage(anyInt(), any());
doAnswer(invocation -> {
Object[] args = invocation.getArguments();
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 c10c3c2..9b25f58 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 @@
assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isFalse();
verify(mDb, times(2)).disableHistory();
}
-
@Test
public void testAddProfile_historyEnabledInPrimary() {
// create a history
@@ -610,4 +609,14 @@
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 53ca704..bf850cf 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.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 @@
}
@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 177d645..dd252f3 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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.time.Instant;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -407,6 +408,7 @@
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 @@
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 @@
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 @@
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 7e92e42..9d7cf53 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 @@
@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 9eed974..9e3e336 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_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.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.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.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.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.
@@ -185,8 +193,9 @@
@TestableLooper.RunWithLooper
public class ZenModeHelperTest extends UiServiceTestCase {
- private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE";
- private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE";
+ private static final String EVENTS_DEFAULT_RULE_ID = ZenModeConfig.EVENTS_DEFAULT_RULE_ID;
+ private static final String SCHEDULE_DEFAULT_RULE_ID =
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID;
private static final String CUSTOM_PKG_NAME = "not.android";
private static final String CUSTOM_APP_LABEL = "This is not Android";
private static final int CUSTOM_PKG_UID = 1;
@@ -231,6 +240,7 @@
@Mock PackageManager mPackageManager;
private Resources mResources;
private TestableLooper mTestableLooper;
+ private final TestClock mTestClock = new TestClock();
private ZenModeHelper mZenModeHelper;
private ContentResolver mContentResolver;
@Mock DeviceEffectsApplier mDeviceEffectsApplier;
@@ -268,7 +278,7 @@
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();
@@ -1197,7 +1207,7 @@
@Test
public void ruleUidAutomaticZenRuleRemovedUpdatesCache() throws Exception {
when(mContext.checkCallingPermission(anyString()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
+ .thenReturn(PERMISSION_GRANTED);
setupZenConfig();
// one enabled automatic rule
@@ -1779,7 +1789,7 @@
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();
@@ -1805,7 +1815,7 @@
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();
@@ -1832,7 +1842,7 @@
// 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();
@@ -2330,6 +2340,68 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void addAutomaticZenRule_withTypeBedtime_replacesDisabledSleeping() {
+ ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
+ sleepingRule.enabled = false;
+ sleepingRule.userModifiedFields = 0;
+ sleepingRule.name = "ZZZZZZZ...";
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mZenModeHelper.mConfig.automaticRules.put(sleepingRule.id, sleepingRule);
+
+ AutomaticZenRule bedtime = new AutomaticZenRule.Builder("Bedtime Mode (TM)", CONDITION_ID)
+ .setType(TYPE_BEDTIME)
+ .build();
+ String bedtimeRuleId = mZenModeHelper.addAutomaticZenRule("pkg", bedtime, UPDATE_ORIGIN_APP,
+ "reason", CUSTOM_PKG_UID);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.keySet()).containsExactly(bedtimeRuleId);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void addAutomaticZenRule_withTypeBedtime_keepsEnabledSleeping() {
+ ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
+ sleepingRule.enabled = true;
+ sleepingRule.userModifiedFields = 0;
+ sleepingRule.name = "ZZZZZZZ...";
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mZenModeHelper.mConfig.automaticRules.put(sleepingRule.id, sleepingRule);
+
+ AutomaticZenRule bedtime = new AutomaticZenRule.Builder("Bedtime Mode (TM)", CONDITION_ID)
+ .setType(TYPE_BEDTIME)
+ .build();
+ String bedtimeRuleId = mZenModeHelper.addAutomaticZenRule("pkg", bedtime, UPDATE_ORIGIN_APP,
+ "reason", CUSTOM_PKG_UID);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.keySet()).containsExactly(
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, bedtimeRuleId);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void addAutomaticZenRule_withTypeBedtime_keepsCustomizedSleeping() {
+ ZenRule sleepingRule = createCustomAutomaticRule(ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID);
+ sleepingRule.enabled = false;
+ sleepingRule.userModifiedFields = AutomaticZenRule.FIELD_INTERRUPTION_FILTER;
+ sleepingRule.name = "ZZZZZZZ...";
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mZenModeHelper.mConfig.automaticRules.put(sleepingRule.id, sleepingRule);
+
+ AutomaticZenRule bedtime = new AutomaticZenRule.Builder("Bedtime Mode (TM)", CONDITION_ID)
+ .setType(TYPE_BEDTIME)
+ .build();
+ String bedtimeRuleId = mZenModeHelper.addAutomaticZenRule("pkg", bedtime, UPDATE_ORIGIN_APP,
+ "reason", CUSTOM_PKG_UID);
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.keySet()).containsExactly(
+ ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID, bedtimeRuleId);
+ }
+
+ @Test
public void testSetManualZenMode() {
mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
setupZenConfig();
@@ -4255,6 +4327,324 @@
}
@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();
@@ -4856,4 +5246,25 @@
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 f5282cb..9bb2da0 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 @@
// 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 @@
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 @@
// 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 98f1843..03d3029 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.runner.RunWith;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Test class for {@link ActivitySnapshotController}.
@@ -45,6 +64,7 @@
public class ActivitySnapshotControllerTests extends WindowTestsBase {
private ActivitySnapshotController mActivitySnapshotController;
+
@Before
public void setUp() throws Exception {
spyOn(mWm.mSnapshotController.mActivitySnapshotController);
@@ -154,4 +174,90 @@
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 d83824a..402cbcc 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 @@
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 8bd5473..2d3c4bb 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.Looper;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
+import android.util.Log;
import androidx.test.filters.MediumTest;
@@ -147,6 +148,8 @@
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 @@
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 e9fe4bb..22ddf84 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.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 @@
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 60e84b0..9c421ba 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 @@
}
/**
+ * 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 c2c0a35..62a2ee5 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 8773cab..1df7012 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.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 @@
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 250c3a5..2a6ac98 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -196,7 +196,7 @@
// 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 @@
// 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 @@
// 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 c7b84a3..73c26a3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9683,6 +9683,17 @@
"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 @@
});
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 @@
* @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 @@
* @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 @@
* @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 @@
*
* @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 @@
* 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 @@
*
* <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 @@
* <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 @@
* 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 @@
* @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 5615602..a5c6d57 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1315,7 +1315,7 @@
* 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 @@
* 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 @@
}
/**
- * 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 @@
* @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 1b47dfe..e4ea479 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6445,10 +6445,6 @@
* 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 @@
* 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 @@
}
/**
- * @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 @@
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 @@
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 @@
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 @@
*
* @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 @@
}
/**
+ * 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 9dd83d1..b6f9e1f 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -451,7 +451,7 @@
/**
* 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 @@
/**
* 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 80e91a3..f04e1c9 100644
--- a/telephony/java/android/telephony/data/DataService.java
+++ b/telephony/java/android/telephony/data/DataService.java
@@ -415,13 +415,13 @@
* 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 @@
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 @@
}
@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 15f8881..c36c302 100644
--- a/telephony/java/android/telephony/data/IDataService.aidl
+++ b/telephony/java/android/telephony/data/IDataService.aidl
@@ -48,5 +48,5 @@
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 54ceaed..9f83da9 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -84,7 +84,7 @@
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 @@
/**
* 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 @@
*/
@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 8842886..d6440fc 100644
--- a/telephony/java/android/telephony/satellite/AntennaPosition.java
+++ b/telephony/java/android/telephony/satellite/AntennaPosition.java
@@ -35,10 +35,10 @@
@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
similarity index 94%
rename from telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl
rename to telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl
index cd9d81e..9ff73e2 100644
--- a/telephony/java/android/telephony/satellite/ISatelliteStateCallback.aidl
+++ b/telephony/java/android/telephony/satellite/ISatelliteModemStateCallback.aidl
@@ -20,7 +20,7 @@
* 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 022a856..9440b65 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 @@
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 b5763c3..8e79ca5 100644
--- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
@@ -22,10 +22,15 @@
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 e09bd20..3b0397b 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -49,8 +49,10 @@
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 @@
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 @@
/**
* 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 @@
@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 @@
* 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 @@
}
}
+ /**
+ * 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
similarity index 96%
rename from telephony/java/android/telephony/satellite/SatelliteStateCallback.java
rename to telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java
index bfe6e10..8d33c88 100644
--- a/telephony/java/android/telephony/satellite/SatelliteStateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteModemStateCallback.java
@@ -28,7 +28,7 @@
*/
@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 9b5ee0c..acbf354 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.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 @@
*/
@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 @@
*/
@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 @@
@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 80c1e5be..217659e 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.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 @@
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 @@
}
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);
}
- // Set expectedFrameRate to 0.0 to verify only stable frame rate.
- private void verifyFrameRate(
- float expectedFrameRate, boolean multiplesAllowed,
+ /** Verify stable frame rate at one of the expectedFrameRates. */
+ private void verifyFrameRates(List<Float> expectedFrameRates, TestSurface... surfaces)
+ throws InterruptedException {
+ verifyFrameRate(expectedFrameRates, true, surfaces);
+ }
+
+ // 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 @@
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 @@
// 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 @@
"**** 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 @@
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 @@
"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 29cbf01..e3988cd 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.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 @@
@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 be479f2..1b02792 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.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 @@
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 @@
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 @@
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 @@
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 c1784f3..7b191f8 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.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 @@
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 @@
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 e50cbc5..71f01ac 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 abc15b4..5aaf30a 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.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 @@
private Handler mHandler;
+ private IBinder mInputToken;
+ private SurfaceControl mSurfaceControl;
+
@Override
public void onCreate() {
super.onCreate();
@@ -101,9 +110,49 @@
}
});
}
+
@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 9e9faf0..6b65b40e 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 @@
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 0000000..e5f8f47
--- /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 f846164..20b7f1f 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 @@
@Test
public void testCreatedTransformsAreApplied() throws Exception {
verifyVcnTransformsApplied(mGatewayConnection, false /* expectForwardTransform */);
+ verify(mUnderlyingNetworkController).updateInboundTransform(any(), any());
}
@Test
@@ -327,6 +328,8 @@
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 692c8a8..49665f7 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.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.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.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 @@
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 edced87..e29e462 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.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 @@
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 @@
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 0000000..9daba6a
--- /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 0000000..6015e931
--- /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 2266041..d85c515 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_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);
+ public void setUp() throws Exception {
+ super.setUp();
- 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);
+ mWifiNetworkRecord = getTestNetworkRecord(WIFI_NETWORK_CAPABILITIES);
+ mCellNetworkRecord = getTestNetworkRecord(CELL_NETWORK_CAPABILITIES);
}
- 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 */);
+ private UnderlyingNetworkRecord getTestNetworkRecord(NetworkCapabilities nc) {
+ return new UnderlyingNetworkRecord(mNetwork, nc, LINK_PROPERTIES, false /* isBlocked */);
}
@Test
@@ -186,14 +82,14 @@
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 @@
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 @@
mWifiNetworkRecord,
SUB_GROUP,
mSubscriptionSnapshot,
- currentlySelected,
+ isSelected,
null /* carrierConfig */));
}
@@ -240,7 +136,7 @@
verifyMatchesPriorityRuleForUpstreamBandwidth(
TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
- null /* currentlySelected */,
+ false /* isSelected */,
true);
}
@@ -249,7 +145,7 @@
verifyMatchesPriorityRuleForUpstreamBandwidth(
LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
- null /* currentlySelected */,
+ false /* isSelected */,
false);
}
@@ -258,7 +154,7 @@
verifyMatchesPriorityRuleForDownstreamBandwidth(
TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
- null /* currentlySelected */,
+ false /* isSelected */,
true);
}
@@ -267,7 +163,7 @@
verifyMatchesPriorityRuleForDownstreamBandwidth(
LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
- null /* currentlySelected */,
+ false /* isSelected */,
false);
}
@@ -276,7 +172,7 @@
verifyMatchesPriorityRuleForUpstreamBandwidth(
TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
- mWifiNetworkRecord,
+ true /* isSelected */,
true);
}
@@ -285,7 +181,7 @@
verifyMatchesPriorityRuleForUpstreamBandwidth(
LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
- mWifiNetworkRecord,
+ true /* isSelected */,
false);
}
@@ -294,7 +190,7 @@
verifyMatchesPriorityRuleForDownstreamBandwidth(
TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
- mWifiNetworkRecord,
+ true /* isSelected */,
true);
}
@@ -303,7 +199,7 @@
verifyMatchesPriorityRuleForDownstreamBandwidth(
LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
- mWifiNetworkRecord,
+ true /* isSelected */,
false);
}
@@ -318,14 +214,12 @@
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 @@
checkMatchesWifiPriorityRule(
wifiNetworkPriority,
mWifiNetworkRecord,
- null /* currentlySelecetd */,
+ false /* isSelected */,
null /* carrierConfig */));
}
@@ -516,7 +410,7 @@
mCellNetworkRecord,
SUB_GROUP,
mSubscriptionSnapshot,
- null /* currentlySelected */,
+ false /* isSelected */,
null /* carrierConfig */));
}
@@ -543,7 +437,16 @@
@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 @@
ncBuilder.addCapability(NET_CAPABILITY_INTERNET);
}
- final UnderlyingNetworkRecord nonDunNetworkRecord =
- getTestNetworkRecord(ncBuilder.build(), templatesRequireDun);
+ final UnderlyingNetworkRecord nonDunNetworkRecord = getTestNetworkRecord(ncBuilder.build());
- assertEquals(expectedPriorityClass, nonDunNetworkRecord.priorityClass);
+ final int priorityClass =
+ NetworkPriorityClassifier.calculatePriorityClass(
+ mVcnContext,
+ nonDunNetworkRecord,
+ templatesRequireDun,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ false /* isSelected */,
+ null /* carrierConfig */);
+
+ 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 2941fde..588624b 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.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 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 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.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 @@
@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 @@
mTestLooper.getLooper(),
mVcnNetworkProvider,
false /* isInTestMode */));
- resetVcnContext();
+ resetVcnContext(mVcnContext);
setupSystemService(
mContext,
@@ -189,18 +198,36 @@
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 @@
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 @@
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 @@
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 @@
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 @@
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
verifyOnSelectedUnderlyingNetworkChanged(expectedRecord);
+ verify(mNetworkEvaluator).setIsSelected(eq(true), any(), any(), any(), any());
return cb;
}
@@ -667,7 +731,7 @@
cb.onBlockedStatusChanged(mNetwork, true /* isBlocked */);
- verifyOnSelectedUnderlyingNetworkChanged(null);
+ verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null);
}
@Test
@@ -675,6 +739,7 @@
UnderlyingNetworkListener cb = verifyRegistrationOnAvailableAndGetCallback();
cb.onLost(mNetwork);
+ verify(mNetworkEvaluator).close();
verify(mNetworkControllerCb).onSelectedUnderlyingNetworkChanged(null);
}
@@ -713,7 +778,8 @@
VcnGatewayConnectionConfigTest.buildTestConfig(networkTemplates),
SUB_GROUP,
mSubscriptionSnapshot,
- mNetworkControllerCb);
+ mNetworkControllerCb,
+ mDependencies);
verify(cm)
.registerNetworkCallback(
@@ -724,30 +790,44 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..aa81efe
--- /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);
+ }
+}